Hi, all I just send you my QUOTA xlator, it is still VERY ALPHA code, but yet usefull to allow devs and people comment and report on funcionality, errors, coding guidelines and so. Quota is a dirty hack over trace and need a lot cleaning :-) but patch compiles cleanly againt tla636 It offers still very limited functionality: - Check limits and reports limited values from stats mops to upper schedulers. - Cheks limits and reports limited values on statsvfs fops (for "df " command) - Check limits on writes, reporting ENOSPC on hitting max-size writes - Checks on unliks computing recovered space. Include docs at /doc/examples/quota.vol Any comments is welcome First Hint: Possible race condiction as quota modifies struct stat *buf from posix-storage as it traverses *_cbk functions Kind Regards, -- ------------------------------------------------ Clist UAH Angel Alvarez ------------------------------------------------ diff -pruN glusterfs-tla636/configure.ac glusterfs-tla636-quota-xlator-0.1/configure.ac --- glusterfs-tla636/configure.ac 2008-01-16 17:19:48.290785081 +0100 +++ glusterfs-tla636-quota-xlator-0.1/configure.ac 2008-01-16 22:43:06.896248606 +0100 @@ -64,6 +64,8 @@ AC_CONFIG_FILES([Makefile xlators/features/fixed-id/src/Makefile xlators/features/trash/Makefile xlators/features/trash/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 -pruN glusterfs-tla636/doc/examples/quota.vol glusterfs-tla636-quota-xlator-0.1/doc/examples/quota.vol --- glusterfs-tla636/doc/examples/quota.vol 1970-01-01 01:00:00.000000000 +0100 +++ glusterfs-tla636-quota-xlator-0.1/doc/examples/quota.vol 2008-01-19 22:27:50.234951911 +0100 @@ -0,0 +1,21 @@ +volume brick + type storage/posix # POSIX FS translator + option directory /home/export # Export this directory +end-volume + +### 'Quota' feature should be added on the server side (as posix volume as subvolume) where it can be used to limit max usage, +on the underlaying block device. +volume quota + type features/quota + subvolumes brick + option max-size 50M # Limit underlaying volume to 50MB of space + option enforce-level # Limit upper schedulers or limit all oprations (CURRENTLY NOT IMPLEMENTED) +end-volume + +volume server + type protocol/server + subvolumes quota brick + option transport-type tcp/server + option auth.ip.brick.allow 192.168.* # Allow access to "brick" volume + option auth.ip.quota.allow 192.168.* # Allow access to "quota" volume (exporting 50MB disk space) +end-volume diff -pruN glusterfs-tla636/doc/translator-option.txt glusterfs-tla636-quota-xlator-0.1/doc/translator-option.txt --- glusterfs-tla636/doc/translator-option.txt 2008-01-16 17:19:48.790813576 +0100 +++ glusterfs-tla636-quota-xlator-0.1/doc/translator-option.txt 2008-01-19 22:22:12.215689291 +0100 @@ -151,6 +151,10 @@ option fixed-uid <n> [if not set, not used] option fixed-gid <n> [if not set, not used] +# features/quota: + option max-size <n> [if not set, not used ] + option enforce-level [0|1] (1) + # features/filter: - NO OPTIONS diff -pruN glusterfs-tla636/xlators/features/Makefile.am glusterfs-tla636-quota-xlator-0.1/xlators/features/Makefile.am --- glusterfs-tla636/xlators/features/Makefile.am 2008-01-16 17:19:52.291013041 +0100 +++ glusterfs-tla636-quota-xlator-0.1/xlators/features/Makefile.am 2008-01-16 22:24:35.832932716 +0100 @@ -1 +1 @@ -SUBDIRS = filter fixed-id posix-locks trash +SUBDIRS = filter fixed-id posix-locks trash quota diff -pruN glusterfs-tla636/xlators/features/quota/Makefile.am glusterfs-tla636-quota-xlator-0.1/xlators/features/quota/Makefile.am --- glusterfs-tla636/xlators/features/quota/Makefile.am 1970-01-01 01:00:00.000000000 +0100 +++ glusterfs-tla636-quota-xlator-0.1/xlators/features/quota/Makefile.am 2008-01-16 17:19:51.000000000 +0100 @@ -0,0 +1 @@ +SUBDIRS = src diff -pruN glusterfs-tla636/xlators/features/quota/src/Makefile.am glusterfs-tla636-quota-xlator-0.1/xlators/features/quota/src/Makefile.am --- glusterfs-tla636/xlators/features/quota/src/Makefile.am 1970-01-01 01:00:00.000000000 +0100 +++ glusterfs-tla636-quota-xlator-0.1/xlators/features/quota/src/Makefile.am 2008-01-16 22:59:55.453723021 +0100 @@ -0,0 +1,11 @@ + +xlator_PROGRAMS = quota.so +xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/quota + +quota_so_SOURCES = quota.c + +AM_CFLAGS = -fPIC -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wall -D$(GF_HOST_OS)\ + -I$(top_srcdir)/libglusterfs/src -shared -nostartfiles + +CLEANFILES = *~ + diff -pruN glusterfs-tla636/xlators/features/quota/src/quota.c glusterfs-tla636-quota-xlator-0.1/xlators/features/quota/src/quota.c --- glusterfs-tla636/xlators/features/quota/src/quota.c 1970-01-01 01:00:00.000000000 +0100 +++ glusterfs-tla636-quota-xlator-0.1/xlators/features/quota/src/quota.c 2008-01-19 22:14:30.689388405 +0100 @@ -0,0 +1,2011 @@ +/* + Copyright (c) 2006, 2007 Z RESEARCH, Inc. <http://www.zresearch.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/>. +*/ + +/** + * xlators/features/quota : + * This translator imposes quota over file operations + * mostly based on trace xlator :-). + * Derive initially by Angel Alvarez clist@xxxxxx + */ + +#include <time.h> +#include <errno.h> +#include "glusterfs.h" +#include "xlator.h" +#include "defaults.h" + + +#define ERR_EINVAL_NORETURN(cond) \ +do \ + { \ + if ((cond)) \ + { \ + gf_log ("ERROR", \ + GF_LOG_ERROR, \ + "%s: %s: (%s) is true", \ + __FILE__, __FUNCTION__, #cond); \ + } \ + } while (0) + +extern int32_t errno; + +#define _FORMAT_WARN(domain, log_level, format, args...) printf ("__DEBUG__" format, ##args); + +struct quota_private { + int32_t debug_flag; + int64_t storage_size; + int64_t disk_usage; + int64_t free_disk; +}; + +struct { + const char *name; + int enabled; +} fop_names[] = {{"stat", 1}, + {"readlink", 1}, + {"mknod", 1}, + {"mkdir", 1}, + {"unlink", 1}, + {"rmdir", 0}, + {"symlink", 0}, + {"rename", 0}, + {"link", 0}, + {"chmod", 0}, + {"chown", 0}, + {"truncate", 0}, + {"open", 0}, + {"read", 0}, + {"write", 1}, + {"statfs", 1}, + {"flush", 0}, + {"close", 0}, + {"fsync", 0}, + {"setxattr", 0}, + {"getxattr", 0}, + {"removexattr", 0}, + {"opendir", 0}, + {"getdents", 0}, + {"closedir", 0}, + {"fsyncdir", 0}, + {"access", 0}, + {"create", 0}, + {"ftruncate", 0}, + {"fstat", 0}, + {"lk", 0}, + {"utimens", 0}, + {"fchmod", 0}, + {"fchown", 0}, + {"lookup", 0}, + {"forget", 0}, + {"setdents", 0}, + {"rmelem", 0}, + {"incver", 0}, + {"readdir", 0},}; + +void +quota_add (xlator_t *this, + int64_t quantity) +{ + struct quota_private *private = NULL; + + if (this) { + gf_log (this->name, + GF_LOG_WARNING, + "QUOTA add (%d)", + quantity); + private = this->private; + private->disk_usage += quantity; + if ( private->disk_usage > private->storage_size ) { + private->free_disk = 0; + } else { + private->free_disk = private->storage_size - private->disk_usage; + } + } +} + +void +quota_sub (xlator_t *this, + int64_t quantity) +{ + struct quota_private *private = NULL; + + if (this) { + gf_log (this->name, + GF_LOG_WARNING, + "QUOTA sub (%d)", + quantity); + private = this->private; + private->disk_usage -= quantity; + if ( private->disk_usage < 0 ) { + private->free_disk = private->storage_size; + } else { + private->free_disk = private->storage_size - private->disk_usage; + } + } +} + +int64_t +quota_check (xlator_t *this) +{ + return ((struct quota_private *)this->private)->free_disk; +} + +void +quota_alter_statvfs (xlator_t *this, + struct statvfs *buf) +{ + struct quota_private *private = NULL; + + private = this->private; + + // set filesystem max blocks + if ( buf->f_blocks > (private->storage_size / buf->f_frsize) ) buf->f_blocks = (private->storage_size / buf->f_frsize); + // set filesystem free blocks for users + buf->f_bfree = private->free_disk / buf->f_frsize; + // FIXME: set filesystem free blocks for root + buf->f_bavail = private->free_disk / buf->f_frsize; + +} + +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 *buf) +{ + int64_t disk_size = quota_check(this); + + ERR_EINVAL_NORETURN (!this); + + // Record bytes written on success + if ( op_ret > 0 ) { + quota_add( this, op_ret ); + } + // If quota is over return error + if ( disk_size == 0 ) { + op_ret = -1; + op_errno = ENOSPC; + gf_log (this->name, + GF_LOG_WARNING, + "No space available! (*this=%p, op_ret=%d, op_errno=%d)", + this, op_ret, op_errno); + } + STACK_UNWIND (frame, op_ret, op_errno, buf); + return 0; +} + +static int32_t +quota_writev (call_frame_t *frame, + xlator_t *this, + fd_t *fd, + struct iovec *vector, + int32_t count, + off_t offset) +{ + ERR_EINVAL_NORETURN (!this || !fd || !vector || (count < 1)); + + STACK_WIND (frame, + quota_writev_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->writev, + fd, vector, count,offset); + 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 stat *buf = NULL; + + ERR_EINVAL_NORETURN (!this ); + buf = frame->local; + if (op_ret >= 0) { + quota_sub(this,buf->st_size); // unlink completed account bytes freed + } else { + // unlik failed? can not account bytes freed + gf_log (this->name, + GF_LOG_WARNING, + "unlink failed! (*this=%p, op_ret=%d, op_errno=%d)", + this, op_ret, op_errno); + } + // free fame->local + frame->local = NULL; + // return to caller + STACK_UNWIND (frame, op_ret, op_errno); + return 0; +} + +static int32_t +quota_pre_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 *loc = NULL; + + ERR_EINVAL_NORETURN (!this); + // Recover loc info from frame (stored by unlink) + loc = frame->local; + //pass buf on frame->local to unlink_cbk + frame->local=buf; + STACK_WIND (frame, + quota_unlink_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->unlink, + loc); + return 0; +} + +static int32_t +quota_unlink (call_frame_t *frame, + xlator_t *this, + loc_t *loc) +{ + ERR_EINVAL_NORETURN (!this || !loc); + + gf_log (this->name, + GF_LOG_WARNING, + " Unlink request path=%s, inode=%p ", + loc->path, loc->inode); + // store loc on frame->local to preserve it + frame->local=loc; + // Call stat to figure out how many bytes will be freed + // Place pre_unlink_stat_cbk on return + STACK_WIND (frame, + quota_pre_unlink_stat_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->stat, + loc); + return 0; +} + +static 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) +{ + + ERR_EINVAL_NORETURN (!this); + + if ( op_ret >= 0 ) { + quota_alter_statvfs (this, buf); + } + STACK_UNWIND (frame, op_ret, op_errno, buf); + return 0; +} + +static int32_t +quota_statfs (call_frame_t *frame, + xlator_t *this, + loc_t *loc) +{ + ERR_EINVAL_NORETURN (!this || !loc); + STACK_WIND (frame, + quota_statfs_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->statfs, + loc); + return 0; +} + + + +//##################################################################################################################### + +static int32_t +quota_fstat_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct stat *buf) +{ + char atime_buf[256], mtime_buf[256], ctime_buf[256]; + ERR_EINVAL_NORETURN (!this ); + + if (fop_names[GF_FOP_FSTAT].enabled) { + if (op_ret >= 0) { + strftime (atime_buf, 256, "[%b %d %H:%M:%S]", localtime (&buf->st_atime)); + strftime (mtime_buf, 256, "[%b %d %H:%M:%S]", localtime (&buf->st_mtime)); + strftime (ctime_buf, 256, "[%b %d %H:%M:%S]", localtime (&buf->st_ctime)); + + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d, *buf=%p {st_dev=%lld, st_ino=%lld, st_mode=%d, st_nlink=%d, st_uid=%d, st_gid=%d, st_rdev=%llx, st_size=%lld, st_blksize=%ld, st_blocks=%lld, st_atime=%s, st_mtime=%s, st_ctime=%s})", + this, op_ret, op_errno, buf, buf->st_dev, buf->st_ino, buf->st_mode, buf->st_nlink, buf->st_uid, buf->st_gid, buf->st_rdev, buf->st_size, buf->st_blksize, buf->st_blocks, atime_buf, mtime_buf, ctime_buf); + } else { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d)", + this, op_ret, op_errno); + } + } + + STACK_UNWIND (frame, op_ret, op_errno, buf); + return 0; +} + +static int32_t +quota_fstat (call_frame_t *frame, + xlator_t *this, + fd_t *fd) +{ + ERR_EINVAL_NORETURN (!this || !fd); + + if (fop_names[GF_FOP_FSTAT].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, *fd=%p)", + this, fd); + } + + STACK_WIND (frame, + quota_fstat_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->fstat, + fd); + 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) +{ + char atime_buf[256], mtime_buf[256], ctime_buf[256]; + ERR_EINVAL_NORETURN (!this); + + if (fop_names[GF_FOP_CREATE].enabled) { + if (op_ret >= 0) { + strftime (atime_buf, 256, "[%b %d %H:%M:%S]", localtime (&buf->st_atime)); + strftime (mtime_buf, 256, "[%b %d %H:%M:%S]", localtime (&buf->st_mtime)); + strftime (ctime_buf, 256, "[%b %d %H:%M:%S]", localtime (&buf->st_ctime)); + + gf_log (this->name, GF_LOG_DEBUG, + "(*this=%s, op_ret=%d, op_errno=%d, fd=%p, inode=%p), *buf=%p {st_dev=%lld, st_ino=%lld, st_mode=%d, st_nlink=%d, st_uid=%d, st_gid=%d, st_rdev=%llx, st_size=%lld, st_blksize=%ld, st_blocks=%lld, st_atime=%s, st_mtime=%s, st_ctime=%s})", + this->name, op_ret, op_errno, fd, inode, buf, buf->st_dev, buf->st_ino, buf->st_mode, buf->st_nlink, buf->st_uid, buf->st_gid, buf->st_rdev, buf->st_size, buf->st_blksize, buf->st_blocks, atime_buf, mtime_buf, ctime_buf); + } else { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d)", + this, op_ret, op_errno); + } + } + + STACK_UNWIND (frame, op_ret, op_errno, fd, inode, buf); + return 0; +} +static int32_t +quota_create (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + int32_t flags, + mode_t mode, + fd_t *fd) +{ + ERR_EINVAL_NORETURN (!this || !loc->path); + + if (fop_names[GF_FOP_CREATE].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, loc=%p {path=%s, inode=%p}, flags=0%o mode=0%o)", + this, loc, loc->path, loc->inode, flags, mode); + } + + STACK_WIND (frame, + quota_create_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->create, + loc, + flags, + mode, + fd); + return 0; +} + +static int32_t +quota_open_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + fd_t *fd) +{ + ERR_EINVAL_NORETURN (!this); + + if (fop_names[GF_FOP_OPEN].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d, *fd=%p)", + this, op_ret, op_errno, fd); + } + + STACK_UNWIND (frame, op_ret, op_errno, fd); + return 0; +} + +static int32_t +quota_open (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + int32_t flags, + fd_t *fd) +{ + ERR_EINVAL_NORETURN (!this || !loc); + + if (fop_names[GF_FOP_OPEN].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, loc=%p {path=%s, inode=%p}, flags=%d, fd=%p)", + this, loc, loc->path, loc->inode, flags, fd); + } + + STACK_WIND (frame, + quota_open_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->open, + loc, + flags, + fd); + return 0; +} + + + + +static int32_t +quota_readv_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct iovec *vector, + int32_t count, + struct stat *buf) +{ + char atime_buf[256], mtime_buf[256], ctime_buf[256]; + ERR_EINVAL_NORETURN (!this); + + if (fop_names[GF_FOP_READ].enabled) { + + if (op_ret >= 0) { + strftime (atime_buf, 256, "[%b %d %H:%M:%S]", localtime (&buf->st_atime)); + strftime (mtime_buf, 256, "[%b %d %H:%M:%S]", localtime (&buf->st_mtime)); + strftime (ctime_buf, 256, "[%b %d %H:%M:%S]", localtime (&buf->st_ctime)); + + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d, *buf=%p {st_dev=%lld, st_ino=%lld, st_mode=%d, st_nlink=%d, st_uid=%d, st_gid=%d, st_rdev=%llx, st_size=%lld, st_blksize=%ld, st_blocks=%lld, st_atime=%s, st_mtime=%s, st_ctime=%s})", + this, op_ret, op_errno, buf, buf->st_dev, buf->st_ino, buf->st_mode, buf->st_nlink, buf->st_uid, buf->st_gid, buf->st_rdev, buf->st_size, buf->st_blksize, buf->st_blocks, atime_buf, mtime_buf, ctime_buf); + } else { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d)", + this, op_ret, op_errno); + } + } + + STACK_UNWIND (frame, op_ret, op_errno, vector, count, buf); + return 0; +} + + + +static int32_t +quota_getdents_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + dir_entry_t *entries, + int32_t count) +{ + ERR_EINVAL_NORETURN (!this ); + + if (fop_names[GF_FOP_GETDENTS].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d, count=%d)", + this, op_ret, op_errno, count); + } + + STACK_UNWIND (frame, op_ret, op_errno, entries, count); + return 0; +} + +static int32_t +quota_fsync_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno) +{ + ERR_EINVAL_NORETURN (!this ); + + if (fop_names[GF_FOP_FSYNC].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d)", + this, op_ret, op_errno); + } + + STACK_UNWIND (frame, op_ret, op_errno); + return 0; +} + +static int32_t +quota_rename_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct stat *buf) +{ + ERR_EINVAL_NORETURN (!this ); + + if (fop_names[GF_FOP_RENAME].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d, buf=%p)", + this, op_ret, op_errno, buf); + } + + STACK_UNWIND (frame, op_ret, op_errno, buf); + return 0; +} + +static int32_t +quota_readlink_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + const char *buf) +{ + ERR_EINVAL_NORETURN (!this ); + + if (fop_names[GF_FOP_READLINK].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d, buf=%s)", + this, op_ret, op_errno, buf); + } + + STACK_UNWIND (frame, op_ret, op_errno, buf); + return 0; +} + +int32_t +quota_lookup_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + inode_t *inode, + struct stat *buf, + dict_t *xattr) +{ + ERR_EINVAL_NORETURN (!this ); + + if (fop_names[GF_FOP_LOOKUP].enabled) { + if (op_ret >= 0) { + gf_log (this->name, + GF_LOG_DEBUG, + "callid: %lld (*this=%p, op_ret=%d, op_errno=%d, inode=%p, *buf=%p {st_dev=%lld, st_ino=%lld, st_mode=%d, st_nlink=%d, st_uid=%d, st_gid=%d, st_rdev=%llx, st_size=%lld, st_blksize=%ld, st_blocks=%lld})", + (long long) frame->root->unique, this, op_ret, op_errno, inode, buf, buf->st_dev, buf->st_ino, buf->st_mode, buf->st_nlink, buf->st_uid, buf->st_gid, buf->st_rdev, buf->st_size, buf->st_blksize, buf->st_blocks); + } else { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d)", + this, op_ret, op_errno); + } + } + + STACK_UNWIND (frame, op_ret, op_errno, inode, buf, xattr); + return 0; +} + +int32_t +quota_forget_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno) +{ + ERR_EINVAL_NORETURN (!this ); + + if (fop_names[GF_FOP_FORGET].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d)", + this, op_ret, op_errno); + } + + STACK_UNWIND (frame, op_ret, op_errno); + 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) +{ + char atime_buf[256], mtime_buf[256], ctime_buf[256]; + ERR_EINVAL_NORETURN (!this ); + + if (fop_names[GF_FOP_SYMLINK].enabled) { + if (op_ret >= 0) { + strftime (atime_buf, 256, "[%b %d %H:%M:%S]", localtime (&buf->st_atime)); + strftime (mtime_buf, 256, "[%b %d %H:%M:%S]", localtime (&buf->st_mtime)); + strftime (ctime_buf, 256, "[%b %d %H:%M:%S]", localtime (&buf->st_ctime)); + + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d, inode=%p, *buf=%p {st_dev=%lld, st_ino=%lld, st_mode=%d, st_nlink=%d, st_uid=%d, st_gid=%d, st_rdev=%llx, st_size=%lld, st_blksize=%ld, st_blocks=%lld, st_atime=%s, st_mtime=%s, st_ctime=%s})", + this, op_ret, op_errno, inode, buf, buf->st_dev, buf->st_ino, buf->st_mode, buf->st_nlink, buf->st_uid, buf->st_gid, buf->st_rdev, buf->st_size, buf->st_blksize, buf->st_blocks, atime_buf, mtime_buf, ctime_buf); + } else { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d)", + this, op_ret, op_errno); + } + } + + STACK_UNWIND (frame, op_ret, op_errno, inode, buf); + 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) +{ + char atime_buf[256], mtime_buf[256], ctime_buf[256]; + ERR_EINVAL_NORETURN (!this ); + + if (fop_names[GF_FOP_MKNOD].enabled) { + if (op_ret >= 0) { + strftime (atime_buf, 256, "[%b %d %H:%M:%S]", localtime (&buf->st_atime)); + strftime (mtime_buf, 256, "[%b %d %H:%M:%S]", localtime (&buf->st_mtime)); + strftime (ctime_buf, 256, "[%b %d %H:%M:%S]", localtime (&buf->st_ctime)); + + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d, inode=%p, *buf=%p {st_dev=%lld, st_ino=%lld, st_mode=%d, st_nlink=%d, st_uid=%d, st_gid=%d, st_rdev=%llx, st_size=%lld, st_blksize=%ld, st_blocks=%lld, st_atime=%s, st_mtime=%s, st_ctime=%s})", + this, op_ret, op_errno, inode, buf, buf->st_dev, buf->st_ino, buf->st_mode, buf->st_nlink, buf->st_uid, buf->st_gid, buf->st_rdev, buf->st_size, buf->st_blksize, buf->st_blocks, atime_buf, mtime_buf, ctime_buf); + } else { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d)", + this, op_ret, op_errno); + } + } + + STACK_UNWIND (frame, op_ret, op_errno, inode, buf); + 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) +{ + ERR_EINVAL_NORETURN (!this ); + + if (fop_names[GF_FOP_MKDIR].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d, inode=%p", + this, op_ret, op_errno, inode); + } + + STACK_UNWIND (frame, op_ret, op_errno, inode, buf); + return 0; +} + +static int32_t +quota_link_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + inode_t *inode, + struct stat *buf) +{ + char atime_buf[256], mtime_buf[256], ctime_buf[256]; + ERR_EINVAL_NORETURN (!this ); + + if (fop_names[GF_FOP_LINK].enabled) { + if (op_ret >= 0) { + strftime (atime_buf, 256, "[%b %d %H:%M:%S]", localtime (&buf->st_atime)); + strftime (mtime_buf, 256, "[%b %d %H:%M:%S]", localtime (&buf->st_mtime)); + strftime (ctime_buf, 256, "[%b %d %H:%M:%S]", localtime (&buf->st_ctime)); + + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d, inode=%p, *buf=%p {st_dev=%lld, st_ino=%lld, st_mode=%d, st_nlink=%d, st_uid=%d, st_gid=%d, st_rdev=%llx, st_size=%lld, st_blksize=%ld, st_blocks=%lld, st_atime=%s, st_mtime=%s, st_ctime=%s})", + this, op_ret, op_errno, inode, buf, buf->st_dev, buf->st_ino, buf->st_mode, buf->st_nlink, buf->st_uid, buf->st_gid, buf->st_rdev, buf->st_size, buf->st_blksize, buf->st_blocks, atime_buf, mtime_buf, ctime_buf); + } else { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d)", + this, op_ret, op_errno); + } + } + + STACK_UNWIND (frame, op_ret, op_errno, inode, buf); + return 0; +} + +static int32_t +quota_flush_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno) +{ + ERR_EINVAL_NORETURN (!this ); + + if (fop_names[GF_FOP_FLUSH].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d)", + this, op_ret, op_errno); + } + + STACK_UNWIND (frame, op_ret, op_errno); + return 0; +} + +static int32_t +quota_close_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno) +{ + ERR_EINVAL_NORETURN (!this ); + + if (fop_names[GF_FOP_CLOSE].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d)", + this, op_ret, op_errno); + } + + STACK_UNWIND (frame, op_ret, op_errno); + return 0; +} + +static int32_t +quota_opendir_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + fd_t *fd) +{ + ERR_EINVAL_NORETURN (!this ); + + if (fop_names[GF_FOP_OPENDIR].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d, fd=%p)", + this, op_ret, op_errno, fd); + } + + STACK_UNWIND (frame, op_ret, op_errno, fd); + 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) +{ + ERR_EINVAL_NORETURN (!this ); + + if (fop_names[GF_FOP_RMDIR].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d)", + this, op_ret, op_errno); + } + + STACK_UNWIND (frame, op_ret, op_errno); + 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) +{ + char atime_buf[256], mtime_buf[256], ctime_buf[256]; + ERR_EINVAL_NORETURN (!this ); + + if (fop_names[GF_FOP_TRUNCATE].enabled) { + if (op_ret >= 0) { + strftime (atime_buf, 256, "[%b %d %H:%M:%S]", localtime (&buf->st_atime)); + strftime (mtime_buf, 256, "[%b %d %H:%M:%S]", localtime (&buf->st_mtime)); + strftime (ctime_buf, 256, "[%b %d %H:%M:%S]", localtime (&buf->st_ctime)); + + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d, *buf=%p {st_dev=%lld, st_ino=%lld, st_mode=%d, st_nlink=%d, st_uid=%d, st_gid=%d, st_rdev=%llx, st_size=%lld, st_blksize=%ld, st_blocks=%lld, st_atime=%s, st_mtime=%s, st_ctime=%s})", + this, op_ret, op_errno, buf, buf->st_dev, buf->st_ino, buf->st_mode, buf->st_nlink, buf->st_uid, buf->st_gid, buf->st_rdev, buf->st_size, buf->st_blksize, buf->st_blocks, atime_buf, mtime_buf, ctime_buf); + } else { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d)", + this, op_ret, op_errno); + } + } + + STACK_UNWIND (frame, op_ret, op_errno, buf); + return 0; +} + +static int32_t +quota_utimens_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct stat *buf) +{ + char atime_buf[256], mtime_buf[256], ctime_buf[256]; + ERR_EINVAL_NORETURN (!this ); + + if (fop_names[GF_FOP_UTIMENS].enabled) { + if (op_ret >= 0) { + strftime (atime_buf, 256, "[%b %d %H:%M:%S]", localtime (&buf->st_atime)); + strftime (mtime_buf, 256, "[%b %d %H:%M:%S]", localtime (&buf->st_mtime)); + strftime (ctime_buf, 256, "[%b %d %H:%M:%S]", localtime (&buf->st_ctime)); + + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d, *buf=%p {st_dev=%lld, st_ino=%lld, st_mode=%d, st_nlink=%d, st_uid=%d, st_gid=%d, st_rdev=%llx, st_size=%lld, st_blksize=%ld, st_blocks=%lld, st_atime=%s, st_mtime=%s, st_ctime=%s})", + this, op_ret, op_errno, buf, buf->st_dev, buf->st_ino, buf->st_mode, buf->st_nlink, buf->st_uid, buf->st_gid, buf->st_rdev, buf->st_size, buf->st_blksize, buf->st_blocks, atime_buf, mtime_buf, ctime_buf); + } else { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d)", + this, op_ret, op_errno); + } + } + + STACK_UNWIND (frame, op_ret, op_errno, buf); + return 0; +} + + +static int32_t +quota_setxattr_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno) +{ + ERR_EINVAL_NORETURN (!this ); + + if (fop_names[GF_FOP_SETXATTR].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d)", + this, op_ret, op_errno); + } + + STACK_UNWIND (frame, op_ret, op_errno); + return 0; +} + +static int32_t +quota_getxattr_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + dict_t *dict) +{ + ERR_EINVAL_NORETURN (!this || !dict); + + if (fop_names[GF_FOP_GETXATTR].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d, dict=%p)", + this, op_ret, op_errno, dict); + } + + STACK_UNWIND (frame, op_ret, op_errno, dict); + return 0; +} + +static int32_t +quota_removexattr_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno) +{ + ERR_EINVAL_NORETURN (!this ); + + if (fop_names[GF_FOP_REMOVEXATTR].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d)", + this, op_ret, op_errno); + } + + STACK_UNWIND (frame, op_ret, op_errno); + return 0; +} + +static int32_t +quota_closedir_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno) +{ + ERR_EINVAL_NORETURN (!this ); + + if (fop_names[GF_FOP_CLOSEDIR].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d)", + this, op_ret, op_errno); + } + + STACK_UNWIND (frame, op_ret, op_errno); + return 0; +} + +static int32_t +quota_fsyncdir_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno) +{ + ERR_EINVAL_NORETURN (!this ); + + if (fop_names[GF_FOP_FSYNCDIR].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d)", + this, op_ret, op_errno); + } + + STACK_UNWIND (frame, op_ret, op_errno); + return 0; +} + +static int32_t +quota_access_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno) +{ + ERR_EINVAL_NORETURN (!this ); + + if (fop_names[GF_FOP_ACCESS].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d)", + this, op_ret, op_errno); + } + + STACK_UNWIND (frame, op_ret, op_errno); + 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) +{ + char atime_buf[256], mtime_buf[256], ctime_buf[256]; + ERR_EINVAL_NORETURN (!this ); + + if (fop_names[GF_FOP_FTRUNCATE].enabled) { + if (op_ret >= 0) { + strftime (atime_buf, 256, "[%b %d %H:%M:%S]", localtime (&buf->st_atime)); + strftime (mtime_buf, 256, "[%b %d %H:%M:%S]", localtime (&buf->st_mtime)); + strftime (ctime_buf, 256, "[%b %d %H:%M:%S]", localtime (&buf->st_ctime)); + + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d, *buf=%p {st_dev=%lld, st_ino=%lld, st_mode=%d, st_nlink=%d, st_uid=%d, st_gid=%d, st_rdev=%llx, st_size=%lld, st_blksize=%ld, st_blocks=%lld, st_atime=%s, st_mtime=%s, st_ctime=%s})", + this, op_ret, op_errno, buf, buf->st_dev, buf->st_ino, buf->st_mode, buf->st_nlink, buf->st_uid, buf->st_gid, buf->st_rdev, buf->st_size, buf->st_blksize, buf->st_blocks, atime_buf, mtime_buf, ctime_buf); + } else { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d)", + this, op_ret, op_errno); + } + } + + STACK_UNWIND (frame, op_ret, op_errno, buf); + return 0; +} + + +static int32_t +quota_lk_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct flock *lock) +{ + ERR_EINVAL_NORETURN (!this ); + + if (fop_names[GF_FOP_LK].enabled) { + if (op_ret >= 0) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d, *lock=%p {l_type=%d, l_whence=%d, l_start=%lld, l_len=%lld, l_pid=%ld})", + this, op_ret, op_errno, lock, + lock->l_type, lock->l_whence, lock->l_start, lock->l_len, lock->l_pid); + } else { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, op_ret=%d, op_errno=%d)", + this, op_ret, op_errno); + } + } + + STACK_UNWIND (frame, op_ret, op_errno, lock); + return 0; +} + + +static int32_t +quota_setdents_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno) +{ + ERR_EINVAL_NORETURN (!this ); + + if (fop_names[GF_FOP_SETDENTS].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "*this=%p, op_ret=%d, op_errno=%d", + this, op_ret, op_errno); + } + + STACK_UNWIND (frame, op_ret, op_errno); + return 0; +} + +int32_t +quota_lookup (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + int32_t need_xattr) +{ + ERR_EINVAL_NORETURN (!this || !loc); + + if (fop_names[GF_FOP_LOOKUP].enabled) { + gf_log (this->name, GF_LOG_DEBUG, + "callid: %lld (*this=%p, loc=%p {path=%s, inode=%p} )", + (long long) frame->root->unique, this, loc, loc->path, + loc->inode, need_xattr); + } + + STACK_WIND (frame, quota_lookup_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->lookup, + loc, need_xattr); + + return 0; +} + +static int32_t +quota_forget (call_frame_t *frame, + xlator_t *this, + inode_t *inode) +{ + ERR_EINVAL_NORETURN (!this || !inode); + + if (fop_names[GF_FOP_FORGET].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "callid: %lld (*this=%p, inode=%p})", + (long long) frame->root->unique, this, inode); + } + + STACK_WIND (frame, + quota_forget_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->forget, + inode); + + return 0; +} + + +static int32_t +quota_readlink (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + size_t size) +{ + ERR_EINVAL_NORETURN (!this || !loc || (size < 1)); + if (fop_names[GF_FOP_READLINK].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, loc=%p {path=%s, inode=%p}, size=%d)", + this, loc, loc->path, loc->inode, size); + } + + STACK_WIND (frame, + quota_readlink_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->readlink, + loc, + size); + + return 0; +} + +static int32_t +quota_mknod (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + mode_t mode, + dev_t dev) +{ + ERR_EINVAL_NORETURN (!this || !loc->path); + + if (fop_names[GF_FOP_MKNOD].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, loc=%p {path=%s, inode=%p}, mode=%d, dev=%lld)", + this, loc, loc->path, loc->inode, mode, dev); + } + + STACK_WIND (frame, + quota_mknod_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->mknod, + loc, + mode, + dev); + + return 0; +} + +static int32_t +quota_mkdir (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + mode_t mode) +{ + ERR_EINVAL_NORETURN (!this || !loc->path); + + if (fop_names[GF_FOP_MKDIR].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, path=%s, loc=%p {path=%s, inode=%p}, mode=%d)", + this, loc->path, loc, loc->inode, mode); + } + + STACK_WIND (frame, + quota_mkdir_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->mkdir, + loc, + mode); + return 0; +} + + +static int32_t +quota_rmdir (call_frame_t *frame, + xlator_t *this, + loc_t *loc) +{ + ERR_EINVAL_NORETURN (!this || !loc); + + if (fop_names[GF_FOP_RMDIR].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, loc=%p {path=%s, inode=%p})", + this, loc, loc->path, loc->inode); + } + + STACK_WIND (frame, + quota_rmdir_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->rmdir, + loc); + + return 0; +} + +static int32_t +quota_symlink (call_frame_t *frame, + xlator_t *this, + const char *linkpath, + loc_t *loc) +{ + ERR_EINVAL_NORETURN (!this || !linkpath || !loc->path); + + if (fop_names[GF_FOP_SYMLINK].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, linkpath=%s, loc=%p {path=%s, inode=%p})", + this, linkpath, loc, loc->path, loc->inode); + } + + STACK_WIND (frame, + quota_symlink_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->symlink, + linkpath, + loc); + + return 0; +} + +static int32_t +quota_rename (call_frame_t *frame, + xlator_t *this, + loc_t *oldloc, + loc_t *newloc) +{ + ERR_EINVAL_NORETURN (!this || !oldloc || !newloc); + + if (fop_names[GF_FOP_RENAME].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, oldloc=%p{path=%s, inode=%p, ino=%ld}, newloc=%p{path=%s, inode=%p, ino=%ld})", + this, oldloc, oldloc->path, oldloc->inode, oldloc->ino, newloc, newloc->path, newloc->inode, newloc->ino); + } + + STACK_WIND (frame, + quota_rename_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->rename, + oldloc, + newloc); + + return 0; +} + +static int32_t +quota_link (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + const char *newpath) +{ + ERR_EINVAL_NORETURN (!this || !loc || !newpath); + + if (fop_names[GF_FOP_LINK].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, loc=%p {path=%s, inode=%p}, newpath=%s)", + this, loc, loc->path, loc->inode, newpath); + } + + STACK_WIND (frame, + quota_link_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->link, + loc, + newpath); + return 0; +} + +static int32_t +quota_truncate (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + off_t offset) +{ + ERR_EINVAL_NORETURN (!this || !loc); + + if (fop_names[GF_FOP_TRUNCATE].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, loc=%p {path=%s, inode=%p}, offset=%lld)", + this, loc, loc->path, loc->inode, offset); + } + + STACK_WIND (frame, + quota_truncate_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->truncate, + loc, + offset); + + return 0; +} + +static int32_t +quota_utimens (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + struct timespec tv[2]) +{ + char actime_str[256]; + char modtime_str[256]; + + ERR_EINVAL_NORETURN (!this || !loc || !tv); + + if (fop_names[GF_FOP_UTIMENS].enabled) { + strftime (actime_str, 256, "[%b %d %H:%M:%S]", localtime (&tv[0].tv_sec)); + strftime (modtime_str, 256, "[%b %d %H:%M:%S]", localtime (&tv[1].tv_sec)); + + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, loc=%p {path=%s, inode=%p}, *tv=%p {actime=%s, modtime=%s})", + this, loc, loc->path, loc->inode, tv, actime_str, modtime_str); + } + + STACK_WIND (frame, + quota_utimens_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->utimens, + loc, + tv); + + return 0; +} + + + +static int32_t +quota_readv (call_frame_t *frame, + xlator_t *this, + fd_t *fd, + size_t size, + off_t offset) +{ + ERR_EINVAL_NORETURN (!this || !fd || (size < 1)); + + if (fop_names[GF_FOP_READ].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, *fd=%p, size=%d, offset=%lld)", + this, fd, size, offset); + } + + STACK_WIND (frame, + quota_readv_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->readv, + fd, + size, + offset); + return 0; +} + + + +static int32_t +quota_flush (call_frame_t *frame, + xlator_t *this, + fd_t *fd) +{ + ERR_EINVAL_NORETURN (!this || !fd); + + if (fop_names[GF_FOP_FLUSH].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, *fd=%p)", + this, fd); + } + + STACK_WIND (frame, + quota_flush_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->flush, + fd); + return 0; +} + +static int32_t +quota_close (call_frame_t *frame, + xlator_t *this, + fd_t *fd) +{ + ERR_EINVAL_NORETURN (!this || !fd); + + if (fop_names[GF_FOP_CLOSE].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, *fd=%p)", + this, fd); + } + + STACK_WIND (frame, + quota_close_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->close, + fd); + return 0; +} + +static int32_t +quota_fsync (call_frame_t *frame, + xlator_t *this, + fd_t *fd, + int32_t flags) +{ + ERR_EINVAL_NORETURN (!this || !fd); + + if (fop_names[GF_FOP_FSYNC].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, flags=%d, *fd=%p)", + this, flags, fd); + } + + STACK_WIND (frame, + quota_fsync_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->fsync, + fd, + flags); + return 0; +} + +static int32_t +quota_setxattr (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + dict_t *dict, + int32_t flags) +{ + ERR_EINVAL_NORETURN (!this || !loc || !dict); + + if (fop_names[GF_FOP_SETXATTR].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, loc=%p {path=%s, inode=%p}, dict=%p, flags=%d)", + this, loc, loc->path, loc->inode, dict, flags); + } + + STACK_WIND (frame, + quota_setxattr_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->setxattr, + loc, + dict, + flags); + return 0; +} + +static int32_t +quota_getxattr (call_frame_t *frame, + xlator_t *this, + loc_t *loc) +{ + ERR_EINVAL_NORETURN (!this || !loc); + + if (fop_names[GF_FOP_GETXATTR].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, loc=%p {path=%s, inode=%p})", + this, loc, loc->path, loc->inode); + } + + STACK_WIND (frame, + quota_getxattr_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->getxattr, + loc); + return 0; +} + +static int32_t +quota_removexattr (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + const char *name) +{ + ERR_EINVAL_NORETURN (!this || !loc || !name); + + if (fop_names[GF_FOP_REMOVEXATTR].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, loc=%p {path=%s, inode=%p}, name=%s)", + this, loc, loc->path, loc->inode, name); + } + + STACK_WIND (frame, + quota_removexattr_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->removexattr, + loc, + name); + + return 0; +} + +static int32_t +quota_opendir (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + fd_t *fd) +{ + ERR_EINVAL_NORETURN (!this || !loc ); + + if (fop_names[GF_FOP_OPENDIR].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "callid: %lld (*this=%p, loc=%p {path=%s, inode=%p}, fd=%p)", + (long long) frame->root->unique, this, loc, loc->path, loc->inode, fd); + } + + STACK_WIND (frame, + quota_opendir_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->opendir, + loc, + fd); + return 0; +} + +static int32_t +quota_getdents (call_frame_t *frame, + xlator_t *this, + fd_t *fd, + size_t size, + off_t offset, + int32_t flag) +{ + ERR_EINVAL_NORETURN (!this || !fd); + + if (fop_names[GF_FOP_GETDENTS].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "callid: %lld (*this=%p, fd=%p, size=%d, offset=%lld, flag=0x%x)", + (long long) frame->root->unique, this, fd, size, offset, flag); + } + + STACK_WIND (frame, + quota_getdents_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->getdents, + fd, + size, + offset, + flag); + return 0; +} + +static int32_t +quota_closedir (call_frame_t *frame, + xlator_t *this, + fd_t *fd) +{ + ERR_EINVAL_NORETURN (!this || !fd); + + if (fop_names[GF_FOP_CLOSEDIR].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "callid: %lld (*this=%p, *fd=%p)", + (long long) frame->root->unique, this, fd); + } + + STACK_WIND (frame, + quota_closedir_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->closedir, + fd); + return 0; +} + +static int32_t +quota_fsyncdir (call_frame_t *frame, + xlator_t *this, + fd_t *fd, + int32_t datasync) +{ + ERR_EINVAL_NORETURN (!this || !fd); + + if (fop_names[GF_FOP_FSYNCDIR].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, datasync=%d, *fd=%p)", + this, datasync, fd); + } + + STACK_WIND (frame, + quota_fsyncdir_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->fsyncdir, + fd, + datasync); + return 0; +} + +static int32_t +quota_access (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + int32_t mask) +{ + ERR_EINVAL_NORETURN (!this || !loc); + + if (fop_names[GF_FOP_ACCESS].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, *loc=%p {path=%s, inode=%p}, mask=%d)", + this, loc, loc->path, loc->inode, mask); + } + + STACK_WIND (frame, + quota_access_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->access, + loc, + mask); + return 0; +} + +static int32_t +quota_ftruncate (call_frame_t *frame, + xlator_t *this, + fd_t *fd, + off_t offset) +{ + ERR_EINVAL_NORETURN (!this || !fd); + + if (fop_names[GF_FOP_FTRUNCATE].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, offset=%lld, *fd=%p)", + this, offset, fd); + } + + STACK_WIND (frame, + quota_ftruncate_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->ftruncate, + fd, + offset); + + return 0; +} + +static int32_t +quota_lk (call_frame_t *frame, + xlator_t *this, + fd_t *fd, + int32_t cmd, + struct flock *lock) +{ + ERR_EINVAL_NORETURN (!this || !fd); + + if (fop_names[GF_FOP_LK].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, *fd=%p, cmd=%d, lock=%p {l_type=%d, l_whence=%d, l_start=%lld, l_len=%lld, l_pid=%ld})", + this, fd, cmd, lock, + lock->l_type, lock->l_whence, lock->l_start, lock->l_len, lock->l_pid); + } + + STACK_WIND (frame, + quota_lk_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->lk, + fd, + cmd, + lock); + return 0; +} + +int32_t +quota_setdents (call_frame_t *frame, + xlator_t *this, + fd_t *fd, + int32_t flags, + dir_entry_t *entries, + int32_t count) +{ + if (fop_names[GF_FOP_SETDENTS].enabled) { + gf_log (this->name, + GF_LOG_DEBUG, + "(*this=%p, *fd=%p, flags=%d, entries=%p count=%d", + this, fd, flags, entries, count); + } + + STACK_WIND (frame, + quota_setdents_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->setdents, + fd, + flags, + entries, + count); + return 0; +} + +int32_t +notify (xlator_t *this, + int32_t event, + void *data, + ...) +{ + struct quota_private *private = NULL; + + private = this->private; + + if (!private) + return 0; + + switch (event) { + case GF_EVENT_CHILD_UP: + { + gf_log (this->name, + GF_LOG_WARNING, + "Notify Event CHILD_UP (%d)\n", event); + default_notify (this, event, data); + } + break; + case GF_EVENT_CHILD_DOWN: + { + gf_log (this->name, + GF_LOG_WARNING, + "Notify Event CHILD_DOWN (%d)\n", event); + default_notify (this, event, data); + } + break; + default: + { + default_notify (this, event, data); + } + } + + return 0; +} + +int32_t +init (xlator_t *this) +{ + +void +gf_log_xlator (xlator_t *this) { + int32_t len; + char *buf; + + if (!this) + return; + + len = dict_serialized_length (this->options); + buf = alloca (len); + dict_serialize (this->options, buf); + + gf_log (this->name, + GF_LOG_WARNING, + "init name=%s, next=%s, parent=%s ", + this->name, this->next->name, this->parent->name); +} + + dict_t *options = this->options; + + struct quota_private *private = calloc (1, sizeof (*private)); + + if (!this) + return -1; + if (!this->children) { + gf_log (this->name, + GF_LOG_ERROR, + "quota translator requires one subvolume"); + return -1; + } + + if (this->children->next) { + gf_log (this->name, + GF_LOG_ERROR, + "quota translator does not support more than one sub-volume"); + return -1; + } + // If parameter "max-size" is set init vars + if (dict_get (this->options, "max-size")) { + private->storage_size = gf_str_to_long_long (data_to_str (dict_get (this->options,"max-size"))); + private->disk_usage = 0; + private->free_disk = private->storage_size; + + gf_log (this->name, GF_LOG_DEBUG, + "Max filesystem size reported = %s", + dict_get (this->options,"max-size")); + } else { + private->storage_size = 0; + } + + //gf_log_set_loglevel (GF_LOG_DEBUG); + + + gf_log_xlator(this); + + /* Set this translator's inode table pointer to child node's pointer. */ + this->itable = FIRST_CHILD (this)->itable; + + this->private = (void *)private; + + + return 0; +} + + +void +fini (xlator_t *this) +{ + if (!this) + return; + + + /* Free up the dictionary options */ + dict_destroy (FIRST_CHILD(this)->options); + + gf_log (this->name, + GF_LOG_DEBUG, + "quota translator unloaded"); + return; +} + +struct xlator_fops fops = { + //.stat = quota_stat, + .readlink = quota_readlink, + .mknod = quota_mknod, + .mkdir = quota_mkdir, + .unlink = quota_unlink, + .rmdir = quota_rmdir, + .symlink = quota_symlink, + .rename = quota_rename, + .link = quota_link, + //.chmod = quota_chmod, + //.chown = quota_chown, + .truncate = quota_truncate, + .utimens = quota_utimens, + .open = quota_open, + .readv = quota_readv, + .writev = quota_writev, + .statfs = quota_statfs, + .flush = quota_flush, + .close = quota_close, + .fsync = quota_fsync, + .setxattr = quota_setxattr, + .getxattr = quota_getxattr, + .removexattr = quota_removexattr, + .opendir = quota_opendir, + //.readdir = quota_readdir, FIXME: implement quota_readdir + .closedir = quota_closedir, + .fsyncdir = quota_fsyncdir, + .access = quota_access, + .ftruncate = quota_ftruncate, + .fstat = quota_fstat, + .create = quota_create, + //.fchown = quota_fchown, + //.fchmod = quota_fchmod, + .lk = quota_lk, + .lookup = quota_lookup, + .forget = quota_forget, + .setdents = quota_setdents, + .getdents = quota_getdents, +}; + +static int32_t +quota_stats_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct xlator_stats *stats) +{ + struct quota_private *private = NULL; + + + private = this->private; + + // Here we control space available to upper modules + if (private->storage_size > 0) { + // Show original values + gf_log (this->name, + GF_LOG_WARNING, + "quota_stats_cbk (Limiting storage in stats_cbk)\n"); + printf ("Pre Limit: %lld Total: %lld Free: %lld Used: %lld \n", + private->storage_size, + stats->total_disk_size, + stats->free_disk, + stats->disk_usage); + // Alter values for enforce limitation + stats->total_disk_size = private->storage_size; + stats->free_disk = private->free_disk; + stats->disk_usage = private->disk_usage; + + printf ("Post Limit: %lld Total: %lld Free: %lld Used: %lld \n", + private->storage_size, + stats->total_disk_size, + stats->free_disk, + stats->disk_usage); + } + STACK_UNWIND (frame, op_ret, op_errno, stats); + return 0; +} + +static int32_t +quota_stats (call_frame_t *frame, + xlator_t *this, + int32_t flags) +{ + ERR_EINVAL_NORETURN (!this); + + { + gf_log (this->name, GF_LOG_DEBUG, "quota_stats (*this=%p, flags=%d\n", this, flags); + + STACK_WIND (frame, + quota_stats_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->mops->stats, + flags); + } + return 0; +} + +struct xlator_mops mops = { + .stats = quota_stats +};