diff options
Diffstat (limited to 'xlators/features/read-only/src')
| -rw-r--r-- | xlators/features/read-only/src/Makefile.am | 11 | ||||
| -rw-r--r-- | xlators/features/read-only/src/read-only-common.c | 413 | ||||
| -rw-r--r-- | xlators/features/read-only/src/read-only-common.h | 116 | ||||
| -rw-r--r-- | xlators/features/read-only/src/read-only-mem-types.h | 20 | ||||
| -rw-r--r-- | xlators/features/read-only/src/read-only.c | 169 | ||||
| -rw-r--r-- | xlators/features/read-only/src/read-only.h | 37 | ||||
| -rw-r--r-- | xlators/features/read-only/src/worm-helper.c | 395 | ||||
| -rw-r--r-- | xlators/features/read-only/src/worm-helper.h | 44 | ||||
| -rw-r--r-- | xlators/features/read-only/src/worm.c | 733 |
9 files changed, 1654 insertions, 284 deletions
diff --git a/xlators/features/read-only/src/Makefile.am b/xlators/features/read-only/src/Makefile.am index 4c146213742..e4a2017ef0d 100644 --- a/xlators/features/read-only/src/Makefile.am +++ b/xlators/features/read-only/src/Makefile.am @@ -2,19 +2,20 @@ xlator_LTLIBRARIES = read-only.la worm.la xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/features -noinst_HEADERS = read-only-common.h +noinst_HEADERS = read-only.h read-only-mem-types.h read-only-common.h worm-helper.h -read_only_la_LDFLAGS = -module -avoid-version +read_only_la_LDFLAGS = -module $(GF_XLATOR_DEFAULT_LDFLAGS) read_only_la_SOURCES = read-only.c read-only-common.c read_only_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la -worm_la_LDFLAGS = -module -avoid-version +worm_la_LDFLAGS = -module $(GF_XLATOR_DEFAULT_LDFLAGS) -worm_la_SOURCES = read-only-common.c worm.c +worm_la_SOURCES = read-only-common.c worm-helper.c worm.c worm_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la -AM_CPPFLAGS = $(GF_CPPFLAGS) -I$(top_srcdir)/libglusterfs/src +AM_CPPFLAGS = $(GF_CPPFLAGS) -I$(top_srcdir)/libglusterfs/src \ + -I$(top_srcdir)/rpc/xdr/src -I$(top_builddir)/rpc/xdr/src AM_CFLAGS = -Wall $(GF_CFLAGS) diff --git a/xlators/features/read-only/src/read-only-common.c b/xlators/features/read-only/src/read-only-common.c index 56a7a7176aa..9640e7e3eee 100644 --- a/xlators/features/read-only/src/read-only-common.c +++ b/xlators/features/read-only/src/read-only-common.c @@ -7,233 +7,400 @@ later), or the GNU General Public License, version 2 (GPLv2), in all cases as published by the Free Software Foundation. */ -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif +#include "read-only.h" +#include "read-only-mem-types.h" +#include <glusterfs/defaults.h> -#include "xlator.h" -#include "defaults.h" +gf_boolean_t +is_readonly_or_worm_enabled(call_frame_t *frame, xlator_t *this) +{ + read_only_priv_t *priv = NULL; + gf_boolean_t readonly_or_worm_enabled = _gf_false; + + priv = this->private; + GF_ASSERT(priv); + + readonly_or_worm_enabled = priv->readonly_or_worm_enabled; + + if (frame->root->pid < GF_CLIENT_PID_MAX) + readonly_or_worm_enabled = _gf_false; + + return readonly_or_worm_enabled; +} + +static int +_check_key_is_zero_filled(dict_t *d, char *k, data_t *v, void *tmp) +{ + if (mem_0filled((const char *)v->data, v->len)) { + /* -1 means, no more iterations, treat as 'break' */ + return -1; + } + return 0; +} int32_t -ro_xattrop (call_frame_t *frame, xlator_t *this, loc_t *loc, - gf_xattrop_flags_t flags, dict_t *dict, dict_t *xdata) +ro_xattrop(call_frame_t *frame, xlator_t *this, loc_t *loc, + gf_xattrop_flags_t flags, dict_t *dict, dict_t *xdata) { - STACK_UNWIND_STRICT (xattrop, frame, -1, EROFS, NULL, xdata); - return 0; + gf_boolean_t allzero = _gf_false; + int ret = 0; + + ret = dict_foreach(dict, _check_key_is_zero_filled, NULL); + if (ret == 0) + allzero = _gf_true; + + if (is_readonly_or_worm_enabled(frame, this) && !allzero) + STACK_UNWIND_STRICT(xattrop, frame, -1, EROFS, NULL, xdata); + else + STACK_WIND_TAIL(frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->xattrop, loc, flags, dict, + xdata); + return 0; } int32_t -ro_fxattrop (call_frame_t *frame, xlator_t *this, - fd_t *fd, gf_xattrop_flags_t flags, dict_t *dict, dict_t *xdata) +ro_fxattrop(call_frame_t *frame, xlator_t *this, fd_t *fd, + gf_xattrop_flags_t flags, dict_t *dict, dict_t *xdata) { - STACK_UNWIND_STRICT (fxattrop, frame, -1, EROFS, NULL, xdata); - return 0; + gf_boolean_t allzero = _gf_false; + int ret = 0; + + ret = dict_foreach(dict, _check_key_is_zero_filled, NULL); + if (ret == 0) + allzero = _gf_true; + + if (is_readonly_or_worm_enabled(frame, this) && !allzero) + STACK_UNWIND_STRICT(fxattrop, frame, -1, EROFS, NULL, xdata); + else + STACK_WIND_TAIL(frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->fxattrop, fd, flags, dict, + xdata); + + return 0; } int32_t -ro_entrylk (call_frame_t *frame, xlator_t *this, const char *volume, - loc_t *loc, const char *basename, entrylk_cmd cmd, - entrylk_type type, dict_t *xdata) +ro_entrylk(call_frame_t *frame, xlator_t *this, const char *volume, loc_t *loc, + const char *basename, entrylk_cmd cmd, entrylk_type type, + dict_t *xdata) { - STACK_UNWIND_STRICT (entrylk, frame, -1, EROFS, xdata); - return 0; + STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->entrylk, + volume, loc, basename, cmd, type, xdata); + + return 0; } int32_t -ro_fentrylk (call_frame_t *frame, xlator_t *this, const char *volume, - fd_t *fd, const char *basename, entrylk_cmd cmd, entrylk_type type, dict_t *xdata) +ro_fentrylk(call_frame_t *frame, xlator_t *this, const char *volume, fd_t *fd, + const char *basename, entrylk_cmd cmd, entrylk_type type, + dict_t *xdata) { - STACK_UNWIND_STRICT (fentrylk, frame, -1, EROFS, xdata); - return 0; + STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->fentrylk, + volume, fd, basename, cmd, type, xdata); + + return 0; } int32_t -ro_inodelk (call_frame_t *frame, xlator_t *this, const char *volume, - loc_t *loc, int32_t cmd, struct gf_flock *lock, dict_t *xdata) +ro_inodelk(call_frame_t *frame, xlator_t *this, const char *volume, loc_t *loc, + int32_t cmd, struct gf_flock *lock, dict_t *xdata) { - STACK_UNWIND_STRICT (inodelk, frame, -1, EROFS, xdata); - return 0; + STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->inodelk, + volume, loc, cmd, lock, xdata); + + return 0; } int32_t -ro_finodelk (call_frame_t *frame, xlator_t *this, const char *volume, - fd_t *fd, int32_t cmd, struct gf_flock *lock, dict_t *xdata) +ro_finodelk(call_frame_t *frame, xlator_t *this, const char *volume, fd_t *fd, + int32_t cmd, struct gf_flock *lock, dict_t *xdata) { - STACK_UNWIND_STRICT (finodelk, frame, -1, EROFS, xdata); - return 0; + STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->finodelk, + volume, fd, cmd, lock, xdata); + + return 0; } int32_t -ro_lk (call_frame_t *frame, xlator_t *this, fd_t *fd, int cmd, - struct gf_flock *flock, dict_t *xdata) +ro_lk(call_frame_t *frame, xlator_t *this, fd_t *fd, int cmd, + struct gf_flock *flock, dict_t *xdata) { - STACK_UNWIND_STRICT (lk, frame, -1, EROFS, NULL, xdata); - return 0; + STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->lk, fd, + cmd, flock, xdata); + + return 0; } int32_t -ro_setattr (call_frame_t *frame, xlator_t *this, loc_t *loc, - struct iatt *stbuf, int32_t valid, dict_t *xdata) +ro_setattr(call_frame_t *frame, xlator_t *this, loc_t *loc, struct iatt *stbuf, + int32_t valid, dict_t *xdata) { - STACK_UNWIND_STRICT (setattr, frame, -1, EROFS, NULL, NULL, xdata); - return 0; + if (is_readonly_or_worm_enabled(frame, this)) + STACK_UNWIND_STRICT(setattr, frame, -1, EROFS, NULL, NULL, xdata); + else + STACK_WIND_TAIL(frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->setattr, loc, stbuf, valid, + xdata); + + return 0; } int32_t -ro_fsetattr (call_frame_t *frame, xlator_t *this, fd_t *fd, - struct iatt *stbuf, int32_t valid, dict_t *xdata) +ro_fsetattr(call_frame_t *frame, xlator_t *this, fd_t *fd, struct iatt *stbuf, + int32_t valid, dict_t *xdata) { - STACK_UNWIND_STRICT (fsetattr, frame, -1, EROFS, NULL, NULL, xdata); - return 0; + if (is_readonly_or_worm_enabled(frame, this)) + STACK_UNWIND_STRICT(fsetattr, frame, -1, EROFS, NULL, NULL, xdata); + else + STACK_WIND_TAIL(frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->fsetattr, fd, stbuf, valid, + xdata); + + return 0; } +int32_t +ro_truncate(call_frame_t *frame, xlator_t *this, loc_t *loc, off_t offset, + dict_t *xdata) +{ + if (is_readonly_or_worm_enabled(frame, this)) + STACK_UNWIND_STRICT(truncate, frame, -1, EROFS, NULL, NULL, xdata); + else + STACK_WIND_TAIL(frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->truncate, loc, offset, xdata); + + return 0; +} int32_t -ro_truncate (call_frame_t *frame, xlator_t *this, loc_t *loc, off_t offset, dict_t *xdata) +ro_ftruncate(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, + dict_t *xdata) { - STACK_UNWIND_STRICT (truncate, frame, -1, EROFS, NULL, NULL, xdata); - return 0; + if (is_readonly_or_worm_enabled(frame, this)) + STACK_UNWIND_STRICT(ftruncate, frame, -1, EROFS, NULL, NULL, xdata); + else + STACK_WIND_TAIL(frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->ftruncate, fd, offset, xdata); + + return 0; } int32_t -ro_ftruncate (call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, dict_t *xdata) +ro_fallocate(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t mode, + off_t offset, size_t len, dict_t *xdata) { - STACK_UNWIND_STRICT (ftruncate, frame, -1, EROFS, NULL, NULL, xdata); - return 0; + if (is_readonly_or_worm_enabled(frame, this)) + STACK_UNWIND_STRICT(fallocate, frame, -1, EROFS, NULL, NULL, xdata); + else + STACK_WIND_TAIL(frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->fallocate, fd, mode, offset, + len, xdata); + return 0; } int -ro_mknod (call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode, - dev_t rdev, mode_t umask, dict_t *xdata) +ro_mknod(call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode, + dev_t rdev, mode_t umask, dict_t *xdata) { - STACK_UNWIND_STRICT (mknod, frame, -1, EROFS, NULL, NULL, NULL, NULL, xdata); - return 0; + if (is_readonly_or_worm_enabled(frame, this)) + STACK_UNWIND_STRICT(mknod, frame, -1, EROFS, NULL, NULL, NULL, NULL, + xdata); + else + STACK_WIND_TAIL(frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->mknod, loc, mode, rdev, umask, + xdata); + + return 0; } - int -ro_mkdir (call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode, - mode_t umask, dict_t *xdata) +ro_mkdir(call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode, + mode_t umask, dict_t *xdata) { - STACK_UNWIND_STRICT (mkdir, frame, -1, EROFS, NULL, NULL, NULL, NULL, xdata); - return 0; + if (is_readonly_or_worm_enabled(frame, this)) + STACK_UNWIND_STRICT(mkdir, frame, -1, EROFS, NULL, NULL, NULL, NULL, + xdata); + else + STACK_WIND_TAIL(frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->mkdir, loc, mode, umask, + xdata); + + return 0; } int32_t -ro_unlink (call_frame_t *frame, xlator_t *this, loc_t *loc, int xflag, - dict_t *xdata) +ro_unlink(call_frame_t *frame, xlator_t *this, loc_t *loc, int xflag, + dict_t *xdata) { - STACK_UNWIND_STRICT (unlink, frame, -1, EROFS, NULL, NULL, xdata); - return 0; -} + if (is_readonly_or_worm_enabled(frame, this)) + STACK_UNWIND_STRICT(unlink, frame, -1, EROFS, NULL, NULL, xdata); + else + STACK_WIND_TAIL(frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->unlink, loc, xflag, xdata); + return 0; +} int -ro_rmdir (call_frame_t *frame, xlator_t *this, loc_t *loc, int flags, - dict_t *xdata) +ro_rmdir(call_frame_t *frame, xlator_t *this, loc_t *loc, int flags, + dict_t *xdata) { - STACK_UNWIND_STRICT (rmdir, frame, -1, EROFS, NULL, NULL, xdata); - return 0; -} + if (is_readonly_or_worm_enabled(frame, this)) + STACK_UNWIND_STRICT(rmdir, frame, -1, EROFS, NULL, NULL, xdata); + else + STACK_WIND_TAIL(frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->rmdir, loc, flags, xdata); + return 0; +} int -ro_symlink (call_frame_t *frame, xlator_t *this, const char *linkpath, - loc_t *loc, mode_t umask, dict_t *xdata) +ro_symlink(call_frame_t *frame, xlator_t *this, const char *linkpath, + loc_t *loc, mode_t umask, dict_t *xdata) { - STACK_UNWIND_STRICT (symlink, frame, -1, EROFS, NULL, NULL, NULL, - NULL, xdata); - return 0; + if (is_readonly_or_worm_enabled(frame, this)) + STACK_UNWIND_STRICT(symlink, frame, -1, EROFS, NULL, NULL, NULL, NULL, + xdata); + else + STACK_WIND_TAIL(frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->symlink, linkpath, loc, umask, + xdata); + + return 0; } - - int32_t -ro_rename (call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc, dict_t *xdata) +ro_rename(call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc, + dict_t *xdata) { - STACK_UNWIND_STRICT (rename, frame, -1, EROFS, NULL, NULL, NULL, NULL, - NULL, xdata); - return 0; + if (is_readonly_or_worm_enabled(frame, this)) + STACK_UNWIND_STRICT(rename, frame, -1, EROFS, NULL, NULL, NULL, NULL, + NULL, xdata); + else + STACK_WIND_TAIL(frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->rename, oldloc, newloc, xdata); + + return 0; } - int32_t -ro_link (call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc, dict_t *xdata) +ro_link(call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc, + dict_t *xdata) { - STACK_UNWIND_STRICT (link, frame, -1, EROFS, NULL, NULL, NULL, NULL, xdata); - return 0; + if (is_readonly_or_worm_enabled(frame, this)) + STACK_UNWIND_STRICT(link, frame, -1, EROFS, NULL, NULL, NULL, NULL, + xdata); + else + STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->link, + oldloc, newloc, xdata); + + return 0; } int32_t -ro_create (call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags, - mode_t mode, mode_t umask, fd_t *fd, dict_t *xdata) +ro_create(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags, + mode_t mode, mode_t umask, fd_t *fd, dict_t *xdata) { - STACK_UNWIND_STRICT (create, frame, -1, EROFS, NULL, NULL, NULL, - NULL, NULL, xdata); - return 0; + if (is_readonly_or_worm_enabled(frame, this)) + STACK_UNWIND_STRICT(create, frame, -1, EROFS, NULL, NULL, NULL, NULL, + NULL, xdata); + else + STACK_WIND_TAIL(frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->create, loc, flags, mode, + umask, fd, xdata); + + return 0; } - static int32_t -ro_open_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, - int32_t op_errno, fd_t *fd, dict_t *xdata) +ro_open_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, + int32_t op_errno, fd_t *fd, dict_t *xdata) { - STACK_UNWIND_STRICT (open, frame, op_ret, op_errno, fd, xdata); - return 0; + STACK_UNWIND_STRICT(open, frame, op_ret, op_errno, fd, xdata); + return 0; } int32_t -ro_open (call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags, - fd_t *fd, dict_t *xdata) +ro_open(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags, + fd_t *fd, dict_t *xdata) { - if (((flags & O_ACCMODE) == O_WRONLY) || - ((flags & O_ACCMODE) == O_RDWR)) { - STACK_UNWIND_STRICT (open, frame, -1, EROFS, NULL, xdata); - return 0; - } + if (is_readonly_or_worm_enabled(frame, this) && + (((flags & O_ACCMODE) == O_WRONLY) || + ((flags & O_ACCMODE) == O_RDWR))) { + STACK_UNWIND_STRICT(open, frame, -1, EROFS, NULL, xdata); + return 0; + } - STACK_WIND (frame, ro_open_cbk, FIRST_CHILD(this), - FIRST_CHILD(this)->fops->open, loc, flags, fd, xdata); - return 0; + STACK_WIND(frame, ro_open_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->open, loc, flags, fd, xdata); + return 0; } int32_t -ro_fsetxattr (call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *dict, - int32_t flags, dict_t *xdata) +ro_fsetxattr(call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *dict, + int32_t flags, dict_t *xdata) { - STACK_UNWIND_STRICT (fsetxattr, frame, -1, EROFS, xdata); - return 0; + if (is_readonly_or_worm_enabled(frame, this)) + STACK_UNWIND_STRICT(fsetxattr, frame, -1, EROFS, xdata); + else + STACK_WIND_TAIL(frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->fsetxattr, fd, dict, flags, + xdata); + + return 0; } int32_t -ro_fsyncdir (call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t flags, dict_t *xdata) +ro_fsyncdir(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t flags, + dict_t *xdata) { - STACK_UNWIND_STRICT (fsyncdir, frame, -1, EROFS, xdata); - return 0; + if (is_readonly_or_worm_enabled(frame, this)) + STACK_UNWIND_STRICT(fsyncdir, frame, -1, EROFS, xdata); + else + STACK_WIND_TAIL(frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->fsyncdir, fd, flags, xdata); + + return 0; } int32_t -ro_writev (call_frame_t *frame, xlator_t *this, fd_t *fd, struct iovec *vector, - int32_t count, off_t off, uint32_t flags, struct iobref *iobref, dict_t *xdata) +ro_writev(call_frame_t *frame, xlator_t *this, fd_t *fd, struct iovec *vector, + int32_t count, off_t off, uint32_t flags, struct iobref *iobref, + dict_t *xdata) { - STACK_UNWIND_STRICT (writev, frame, -1, EROFS, NULL, NULL, xdata); - return 0; + if (is_readonly_or_worm_enabled(frame, this)) + STACK_UNWIND_STRICT(writev, frame, -1, EROFS, NULL, NULL, xdata); + else + STACK_WIND_TAIL(frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->writev, fd, vector, count, off, + flags, iobref, xdata); + + return 0; } - int32_t -ro_setxattr (call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *dict, - int32_t flags, dict_t *xdata) +ro_setxattr(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *dict, + int32_t flags, dict_t *xdata) { - STACK_UNWIND_STRICT (setxattr, frame, -1, EROFS, xdata); - return 0; + if (is_readonly_or_worm_enabled(frame, this)) + STACK_UNWIND_STRICT(setxattr, frame, -1, EROFS, xdata); + else + STACK_WIND_TAIL(frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->setxattr, loc, dict, flags, + xdata); + + return 0; } int32_t -ro_removexattr (call_frame_t *frame, xlator_t *this, loc_t *loc, - const char *name, dict_t *xdata) +ro_removexattr(call_frame_t *frame, xlator_t *this, loc_t *loc, + const char *name, dict_t *xdata) { - STACK_UNWIND_STRICT (removexattr, frame, -1, EROFS, xdata); - return 0; + if (is_readonly_or_worm_enabled(frame, this)) + STACK_UNWIND_STRICT(removexattr, frame, -1, EROFS, xdata); + else + STACK_WIND_TAIL(frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->removexattr, loc, name, xdata); + + return 0; } diff --git a/xlators/features/read-only/src/read-only-common.h b/xlators/features/read-only/src/read-only-common.h index 5d4c7e260ed..5561961ffa2 100644 --- a/xlators/features/read-only/src/read-only-common.h +++ b/xlators/features/read-only/src/read-only-common.h @@ -7,109 +7,115 @@ later), or the GNU General Public License, version 2 (GPLv2), in all cases as published by the Free Software Foundation. */ -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif +#include <glusterfs/xlator.h> +#include <glusterfs/defaults.h> -#include "xlator.h" -#include "defaults.h" +gf_boolean_t +is_readonly_or_worm_enabled(call_frame_t *frame, xlator_t *this); int32_t -ro_xattrop (call_frame_t *frame, xlator_t *this, loc_t *loc, - gf_xattrop_flags_t flags, dict_t *dict, dict_t *xdata); +ro_xattrop(call_frame_t *frame, xlator_t *this, loc_t *loc, + gf_xattrop_flags_t flags, dict_t *dict, dict_t *xdata); int32_t -ro_fxattrop (call_frame_t *frame, xlator_t *this, - fd_t *fd, gf_xattrop_flags_t flags, dict_t *dict, dict_t *xdata); +ro_fxattrop(call_frame_t *frame, xlator_t *this, fd_t *fd, + gf_xattrop_flags_t flags, dict_t *dict, dict_t *xdata); int32_t -ro_entrylk (call_frame_t *frame, xlator_t *this, const char *volume, - loc_t *loc, const char *basename, entrylk_cmd cmd, - entrylk_type type, dict_t *xdata); +ro_entrylk(call_frame_t *frame, xlator_t *this, const char *volume, loc_t *loc, + const char *basename, entrylk_cmd cmd, entrylk_type type, + dict_t *xdata); int32_t -ro_fentrylk (call_frame_t *frame, xlator_t *this, const char *volume, - fd_t *fd, const char *basename, entrylk_cmd cmd, entrylk_type - type, dict_t *xdata); +ro_fentrylk(call_frame_t *frame, xlator_t *this, const char *volume, fd_t *fd, + const char *basename, entrylk_cmd cmd, entrylk_type type, + dict_t *xdata); int32_t -ro_inodelk (call_frame_t *frame, xlator_t *this, const char *volume, - loc_t *loc, int32_t cmd, struct gf_flock *lock, dict_t *xdata); +ro_inodelk(call_frame_t *frame, xlator_t *this, const char *volume, loc_t *loc, + int32_t cmd, struct gf_flock *lock, dict_t *xdata); int32_t -ro_finodelk (call_frame_t *frame, xlator_t *this, const char *volume, - fd_t *fd, int32_t cmd, struct gf_flock *lock, dict_t *xdata); +ro_finodelk(call_frame_t *frame, xlator_t *this, const char *volume, fd_t *fd, + int32_t cmd, struct gf_flock *lock, dict_t *xdata); int32_t -ro_lk (call_frame_t *frame, xlator_t *this, fd_t *fd, int cmd, - struct gf_flock *flock, dict_t *xdata); +ro_lk(call_frame_t *frame, xlator_t *this, fd_t *fd, int cmd, + struct gf_flock *flock, dict_t *xdata); int32_t -ro_setattr (call_frame_t *frame, xlator_t *this, loc_t *loc, - struct iatt *stbuf, int32_t valid, dict_t *xdata); +ro_setattr(call_frame_t *frame, xlator_t *this, loc_t *loc, struct iatt *stbuf, + int32_t valid, dict_t *xdata); int32_t -ro_fsetattr (call_frame_t *frame, xlator_t *this, fd_t *fd, - struct iatt *stbuf, int32_t valid, dict_t *xdata); - +ro_fsetattr(call_frame_t *frame, xlator_t *this, fd_t *fd, struct iatt *stbuf, + int32_t valid, dict_t *xdata); int32_t -ro_truncate (call_frame_t *frame, xlator_t *this, loc_t *loc, off_t offset, dict_t *xdata); +ro_truncate(call_frame_t *frame, xlator_t *this, loc_t *loc, off_t offset, + dict_t *xdata); int32_t -ro_ftruncate (call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, dict_t *xdata); +ro_ftruncate(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, + dict_t *xdata); int -ro_mknod (call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode, - dev_t rdev, mode_t umask, dict_t *xdata); +ro_mknod(call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode, + dev_t rdev, mode_t umask, dict_t *xdata); int -ro_mkdir (call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode, - mode_t umask, dict_t *xdata); +ro_mkdir(call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode, + mode_t umask, dict_t *xdata); int32_t -ro_unlink (call_frame_t *frame, xlator_t *this, loc_t *loc, int xflag, - dict_t *xdata); - -int -ro_rmdir (call_frame_t *frame, xlator_t *this, loc_t *loc, int flags, +ro_unlink(call_frame_t *frame, xlator_t *this, loc_t *loc, int xflag, dict_t *xdata); +int +ro_rmdir(call_frame_t *frame, xlator_t *this, loc_t *loc, int flags, + dict_t *xdata); int -ro_symlink (call_frame_t *frame, xlator_t *this, const char *linkpath, - loc_t *loc, mode_t umask, dict_t *xdata); +ro_symlink(call_frame_t *frame, xlator_t *this, const char *linkpath, + loc_t *loc, mode_t umask, dict_t *xdata); int32_t -ro_rename (call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc, dict_t *xdata); +ro_rename(call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc, + dict_t *xdata); int32_t -ro_link (call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc, dict_t *xdata); +ro_link(call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc, + dict_t *xdata); int32_t -ro_create (call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags, - mode_t mode, mode_t umask, fd_t *fd, dict_t *xdata); +ro_create(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags, + mode_t mode, mode_t umask, fd_t *fd, dict_t *xdata); int32_t -ro_open (call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags, - fd_t *fd, dict_t *xdata); +ro_open(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags, + fd_t *fd, dict_t *xdata); int32_t -ro_fsetxattr (call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *dict, - int32_t flags, dict_t *xdata); +ro_fsetxattr(call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *dict, + int32_t flags, dict_t *xdata); int32_t -ro_fsyncdir (call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t flags, dict_t *xdata); +ro_fsyncdir(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t flags, + dict_t *xdata); int32_t -ro_writev (call_frame_t *frame, xlator_t *this, fd_t *fd, struct iovec *vector, - int32_t count, off_t off, uint32_t flags, struct iobref *iobref, dict_t *xdata); +ro_writev(call_frame_t *frame, xlator_t *this, fd_t *fd, struct iovec *vector, + int32_t count, off_t off, uint32_t flags, struct iobref *iobref, + dict_t *xdata); int32_t -ro_setxattr (call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *dict, - int32_t flags, dict_t *xdata); +ro_setxattr(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *dict, + int32_t flags, dict_t *xdata); + +int32_t +ro_removexattr(call_frame_t *frame, xlator_t *this, loc_t *loc, + const char *name, dict_t *xdata); int32_t -ro_removexattr (call_frame_t *frame, xlator_t *this, loc_t *loc, - const char *name, dict_t *xdata); +ro_fallocate(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t mode, + off_t offset, size_t len, dict_t *xdata); diff --git a/xlators/features/read-only/src/read-only-mem-types.h b/xlators/features/read-only/src/read-only-mem-types.h new file mode 100644 index 00000000000..c67d6c02cd0 --- /dev/null +++ b/xlators/features/read-only/src/read-only-mem-types.h @@ -0,0 +1,20 @@ +/* + Copyright (c) 2014 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#ifndef __READONLY_MEM_TYPES_H__ +#define __READONLY_MEM_TYPES_H__ + +#include <glusterfs/mem-types.h> + +enum gf_read_only_mem_types_ { + gf_read_only_mt_priv_t = gf_common_mt_end + 1, + gf_read_only_mt_end +}; +#endif diff --git a/xlators/features/read-only/src/read-only.c b/xlators/features/read-only/src/read-only.c index e49e54a1b31..48654998e63 100644 --- a/xlators/features/read-only/src/read-only.c +++ b/xlators/features/read-only/src/read-only.c @@ -7,71 +7,138 @@ later), or the GNU General Public License, version 2 (GPLv2), in all cases as published by the Free Software Foundation. */ -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include "xlator.h" -#include "defaults.h" #include "read-only-common.h" +#include "read-only-mem-types.h" +#include "read-only.h" int32_t -init (xlator_t *this) +mem_acct_init(xlator_t *this) { - if (!this->children || this->children->next) { - gf_log (this->name, GF_LOG_ERROR, - "translator not configured with exactly one child"); - return -1; - } - - if (!this->parents) { - gf_log (this->name, GF_LOG_WARNING, - "dangling volume. check volfile "); - } - - return 0; + int ret = -1; + + ret = xlator_mem_acct_init(this, gf_read_only_mt_end + 1); + if (ret) + gf_log(this->name, GF_LOG_ERROR, + "Memory accounting " + "initialization failed."); + + return ret; } +int32_t +init(xlator_t *this) +{ + int ret = -1; + read_only_priv_t *priv = NULL; -void -fini (xlator_t *this) + if (!this->children || this->children->next) { + gf_log(this->name, GF_LOG_ERROR, + "translator not configured with exactly one child"); + return -1; + } + + if (!this->parents) { + gf_log(this->name, GF_LOG_WARNING, "dangling volume. check volfile "); + } + + priv = GF_CALLOC(1, sizeof(*priv), gf_read_only_mt_priv_t); + if (!priv) + goto out; + + this->private = priv; + + GF_OPTION_INIT("read-only", priv->readonly_or_worm_enabled, bool, out); + + ret = 0; +out: + return ret; +} + +int +reconfigure(xlator_t *this, dict_t *options) { - return; + read_only_priv_t *priv = NULL; + int ret = -1; + gf_boolean_t readonly_or_worm_enabled = _gf_false; + + priv = this->private; + GF_ASSERT(priv); + + GF_OPTION_RECONF("read-only", readonly_or_worm_enabled, options, bool, out); + priv->readonly_or_worm_enabled = readonly_or_worm_enabled; + ret = 0; +out: + gf_log(this->name, GF_LOG_DEBUG, "returning %d", ret); + return ret; } +void +fini(xlator_t *this) +{ + read_only_priv_t *priv = NULL; + + priv = this->private; + if (!priv) + return; + + this->private = NULL; + GF_FREE(priv); + + return; +} struct xlator_fops fops = { - .mknod = ro_mknod, - .mkdir = ro_mkdir, - .unlink = ro_unlink, - .rmdir = ro_rmdir, - .symlink = ro_symlink, - .rename = ro_rename, - .link = ro_link, - .truncate = ro_truncate, - .open = ro_open, - .writev = ro_writev, - .setxattr = ro_setxattr, - .fsetxattr = ro_fsetxattr, - .removexattr = ro_removexattr, - .fsyncdir = ro_fsyncdir, - .ftruncate = ro_ftruncate, - .create = ro_create, - .setattr = ro_setattr, - .fsetattr = ro_fsetattr, - .xattrop = ro_xattrop, - .fxattrop = ro_fxattrop, - .inodelk = ro_inodelk, - .finodelk = ro_finodelk, - .entrylk = ro_entrylk, - .fentrylk = ro_fentrylk, - .lk = ro_lk, + .mknod = ro_mknod, + .mkdir = ro_mkdir, + .unlink = ro_unlink, + .rmdir = ro_rmdir, + .symlink = ro_symlink, + .rename = ro_rename, + .link = ro_link, + .truncate = ro_truncate, + .open = ro_open, + .writev = ro_writev, + .setxattr = ro_setxattr, + .fsetxattr = ro_fsetxattr, + .removexattr = ro_removexattr, + .fsyncdir = ro_fsyncdir, + .ftruncate = ro_ftruncate, + .create = ro_create, + .setattr = ro_setattr, + .fsetattr = ro_fsetattr, + .xattrop = ro_xattrop, + .fxattrop = ro_fxattrop, + .inodelk = ro_inodelk, + .finodelk = ro_finodelk, + .entrylk = ro_entrylk, + .fentrylk = ro_fentrylk, + .lk = ro_lk, + .fallocate = ro_fallocate, }; -struct xlator_cbks cbks = { -}; +struct xlator_cbks cbks = {}; struct volume_options options[] = { - { .key = {NULL} }, + {.key = {"read-only"}, + .type = GF_OPTION_TYPE_BOOL, + .default_value = "off", + /*.validate_fn = validate_boolean,*/ + .op_version = {1}, + .flags = OPT_FLAG_SETTABLE, + .description = "When \"on\", makes a volume read-only. It is turned " + "\"off\" by default."}, + {.key = {NULL}}, +}; + +xlator_api_t xlator_api = { + .init = init, + .fini = fini, + .reconfigure = reconfigure, + .mem_acct_init = mem_acct_init, + .op_version = {1}, /* Present from the initial version */ + .fops = &fops, + .cbks = &cbks, + .options = options, + .identifier = "read-only", + .category = GF_TECH_PREVIEW, }; diff --git a/xlators/features/read-only/src/read-only.h b/xlators/features/read-only/src/read-only.h new file mode 100644 index 00000000000..aced5d3c577 --- /dev/null +++ b/xlators/features/read-only/src/read-only.h @@ -0,0 +1,37 @@ +/* + Copyright (c) 2014 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#ifndef __READONLY_H__ +#define __READONLY_H__ + +#include <stdint.h> // for uint64_t, uint8_t +#include <sys/time.h> // for time_t +#include "glusterfs/glusterfs.h" // for gf_boolean_t + +typedef struct { + uint8_t worm : 1; + uint8_t retain : 1; + uint8_t legal_hold : 1; + uint8_t ret_mode : 1; + int64_t ret_period; + int64_t auto_commit_period; +} worm_reten_state_t; + +typedef struct { + gf_boolean_t readonly_or_worm_enabled; + gf_boolean_t worm_file; + gf_boolean_t worm_files_deletable; + int64_t reten_period; + int64_t com_period; + int reten_mode; + time_t start_time; +} read_only_priv_t; + +#endif diff --git a/xlators/features/read-only/src/worm-helper.c b/xlators/features/read-only/src/worm-helper.c new file mode 100644 index 00000000000..df45f2a940b --- /dev/null +++ b/xlators/features/read-only/src/worm-helper.c @@ -0,0 +1,395 @@ +/* + Copyright (c) 2016 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ +#include "read-only-mem-types.h" +#include "read-only.h" +#include <glusterfs/xlator.h> +#include <glusterfs/syncop.h> +#include "worm-helper.h" + +/*Function to check whether file is read-only. + * The input *stbuf contains the attributes of the file, which is used to check + * the write protection bits for all the users of the file. + * Return true if all the write bits are disabled,false otherwise*/ +gf_boolean_t +gf_worm_write_disabled(struct iatt *stbuf) +{ + gf_boolean_t ret = _gf_false; + + GF_VALIDATE_OR_GOTO("worm", stbuf, out); + + if (stbuf->ia_prot.owner.write == 0 && stbuf->ia_prot.group.write == 0 && + stbuf->ia_prot.other.write == 0) + ret = _gf_true; +out: + return ret; +} + +int32_t +worm_init_state(xlator_t *this, gf_boolean_t fop_with_fd, void *file_ptr) +{ + int ret = -1; + uint64_t start_time = 0; + dict_t *dict = NULL; + + GF_VALIDATE_OR_GOTO("worm", this, out); + GF_VALIDATE_OR_GOTO(this->name, file_ptr, out); + + start_time = gf_time(); + dict = dict_new(); + if (!dict) { + gf_log(this->name, GF_LOG_ERROR, "Error creating the dict"); + goto out; + } + ret = dict_set_uint64(dict, "trusted.start_time", start_time); + if (ret) { + gf_log(this->name, GF_LOG_ERROR, "Error in setting the dict"); + goto out; + } + if (fop_with_fd) + ret = syncop_fsetxattr(this, (fd_t *)file_ptr, dict, 0, NULL, NULL); + else + ret = syncop_setxattr(this, (loc_t *)file_ptr, dict, 0, NULL, NULL); +out: + if (dict) + dict_unref(dict); + return ret; +} + +/*Function to set the retention state for a file. + * It loads the WORM/Retention state into the retention_state pointer.*/ +int32_t +worm_set_state(xlator_t *this, gf_boolean_t fop_with_fd, void *file_ptr, + worm_reten_state_t *retention_state, struct iatt *stbuf) +{ + read_only_priv_t *priv = NULL; + struct iatt stpre = { + 0, + }; + int ret = -1; + + GF_VALIDATE_OR_GOTO("worm", this, out); + GF_VALIDATE_OR_GOTO(this->name, file_ptr, out); + GF_VALIDATE_OR_GOTO(this->name, retention_state, out); + GF_VALIDATE_OR_GOTO(this->name, stbuf, out); + + priv = this->private; + GF_ASSERT(priv); + retention_state->worm = 1; + retention_state->retain = 1; + retention_state->legal_hold = 0; + retention_state->ret_mode = priv->reten_mode; + retention_state->ret_period = priv->reten_period; + retention_state->auto_commit_period = priv->com_period; + if (fop_with_fd) + ret = syncop_fstat(this, (fd_t *)file_ptr, &stpre, NULL, NULL); + else + ret = syncop_stat(this, (loc_t *)file_ptr, &stpre, NULL, NULL); + if (ret) + goto out; + stbuf->ia_mtime = stpre.ia_mtime; + stbuf->ia_atime = gf_time() + retention_state->ret_period; + + if (fop_with_fd) + ret = syncop_fsetattr(this, (fd_t *)file_ptr, stbuf, GF_SET_ATTR_ATIME, + NULL, NULL, NULL, NULL); + else + ret = syncop_setattr(this, (loc_t *)file_ptr, stbuf, GF_SET_ATTR_ATIME, + NULL, NULL, NULL, NULL); + if (ret) + goto out; + + ret = gf_worm_set_xattr(this, retention_state, fop_with_fd, file_ptr); + if (ret) { + gf_log(this->name, GF_LOG_ERROR, "Error setting xattr"); + goto out; + } + ret = 0; +out: + return ret; +} + +/*This function gets the state of the WORM/Retention xattr and loads it in the + * dict pointer.*/ +int32_t +worm_get_state(xlator_t *this, gf_boolean_t fop_with_fd, void *file_ptr, + worm_reten_state_t *reten_state) +{ + dict_t *dict = NULL; + char *val = NULL; + int ret = -1; + + GF_VALIDATE_OR_GOTO("worm", this, out); + GF_VALIDATE_OR_GOTO(this->name, file_ptr, out); + GF_VALIDATE_OR_GOTO(this->name, reten_state, out); + + if (fop_with_fd) + ret = syncop_fgetxattr(this, (fd_t *)file_ptr, &dict, + "trusted.reten_state", NULL, NULL); + else + ret = syncop_getxattr(this, (loc_t *)file_ptr, &dict, + "trusted.reten_state", NULL, NULL); + if (ret < 0 || !dict) { + ret = -1; + goto out; + } + ret = dict_get_str(dict, "trusted.reten_state", &val); + if (ret) { + ret = -2; + gf_log(this->name, GF_LOG_ERROR, "Empty val"); + } + gf_worm_deserialize_state(val, reten_state); +out: + if (dict) + dict_unref(dict); + return ret; +} + +/*Function to lookup the current state of the WORM/Retention profile. + * Based on the retain value and the access time of the file, the transition + * from WORM/Retention to WORM is made.*/ +void +gf_worm_state_lookup(xlator_t *this, gf_boolean_t fop_with_fd, void *file_ptr, + worm_reten_state_t *reten_state, struct iatt *stbuf) +{ + int ret = -1; + + GF_VALIDATE_OR_GOTO("worm", this, out); + GF_VALIDATE_OR_GOTO(this->name, file_ptr, out); + GF_VALIDATE_OR_GOTO(this->name, reten_state, out); + GF_VALIDATE_OR_GOTO(this->name, stbuf, out); + + stbuf->ia_atime -= reten_state->ret_period; + reten_state->retain = 0; + reten_state->ret_period = 0; + reten_state->auto_commit_period = 0; + ret = gf_worm_set_xattr(this, reten_state, fop_with_fd, file_ptr); + if (ret) { + gf_log(this->name, GF_LOG_ERROR, "Error setting xattr"); + goto out; + } + + if (fop_with_fd) + ret = syncop_fsetattr(this, (fd_t *)file_ptr, stbuf, GF_SET_ATTR_ATIME, + NULL, NULL, NULL, NULL); + else + ret = syncop_setattr(this, (loc_t *)file_ptr, stbuf, GF_SET_ATTR_ATIME, + NULL, NULL, NULL, NULL); + if (ret) + goto out; + gf_log(this->name, GF_LOG_INFO, "Retention state reset"); +out: + return; +} + +/*This function serializes and stores the WORM/Retention state of a file in an + * uint64_t variable by setting the bits using the bitwise operations.*/ +void +gf_worm_serialize_state(worm_reten_state_t *reten_state, char *val) +{ + uint32_t state = 0; + + GF_VALIDATE_OR_GOTO("worm", reten_state, out); + GF_VALIDATE_OR_GOTO("worm", val, out); + + state |= reten_state->worm << 0; + state |= reten_state->retain << 1; + state |= reten_state->legal_hold << 2; + state |= reten_state->ret_mode << 3; + sprintf(val, "%d/%" PRIu64 "/%" PRIu64, state, reten_state->ret_period, + reten_state->auto_commit_period); + +out: + return; +} + +/*This function deserializes the data stored in the xattr of the file and loads + * the value to the reten_state structure.*/ +void +gf_worm_deserialize_state(char *val, worm_reten_state_t *reten_state) +{ + char *token = NULL; + uint32_t state = 0; + + GF_VALIDATE_OR_GOTO("worm", val, out); + GF_VALIDATE_OR_GOTO("worm", reten_state, out); + + token = strtok(val, "/"); + state = atoi(token); + reten_state->worm = (state >> 0) & 1; + reten_state->retain = (state >> 1) & 1; + reten_state->legal_hold = (state >> 2) & 1; + reten_state->ret_mode = (state >> 3) & 1; + token = strtok(NULL, "/"); + reten_state->ret_period = atoi(token); + token = strtok(NULL, "/"); + reten_state->auto_commit_period = atoi(token); + +out: + return; +} + +/*Function to set the xattr for a file. + * If the xattr is already present then it will replace that.*/ +int32_t +gf_worm_set_xattr(xlator_t *this, worm_reten_state_t *reten_state, + gf_boolean_t fop_with_fd, void *file_ptr) +{ + char val[100] = ""; + int ret = -1; + dict_t *dict = NULL; + + GF_VALIDATE_OR_GOTO("worm", this, out); + GF_VALIDATE_OR_GOTO(this->name, reten_state, out); + GF_VALIDATE_OR_GOTO(this->name, file_ptr, out); + + gf_worm_serialize_state(reten_state, val); + dict = dict_new(); + if (!dict) { + gf_log(this->name, GF_LOG_ERROR, "Error creating the dict"); + goto out; + } + ret = dict_set_str(dict, "trusted.reten_state", val); + if (ret) { + gf_log(this->name, GF_LOG_ERROR, "Error in setting the dict"); + goto out; + } + if (fop_with_fd) + ret = syncop_fsetxattr(this, (fd_t *)file_ptr, dict, 0, NULL, NULL); + else + ret = syncop_setxattr(this, (loc_t *)file_ptr, dict, 0, NULL, NULL); +out: + if (dict) + dict_unref(dict); + return ret; +} + +/*This function checks whether a file's timeout is happened for the state + * transition and if yes, then it will do the transition from the current state + * to the appropriate state. It also decides whether to continue or to block + * the FOP. + * Return: + * 0 : If the FOP should continue i.e., if the file is not in the WORM-Retained + * state or if the FOP is unlink and the file is not in the Retained state. + * 1: If the FOP sholud block i.e., if the file is in WORM-Retained/WORM state. + * 2: Blocks the FOP if any operation fails while doing the state transition or + * fails to get the state of the file.*/ +int +gf_worm_state_transition(xlator_t *this, gf_boolean_t fop_with_fd, + void *file_ptr, glusterfs_fop_t op) +{ + int op_errno = EROFS; + int ret = -1; + time_t now = 0; + uint64_t com_period = 0; + uint64_t start_time = 0; + dict_t *dict = NULL; + worm_reten_state_t reten_state = { + 0, + }; + read_only_priv_t *priv = NULL; + struct iatt stbuf = { + 0, + }; + + priv = this->private; + GF_ASSERT(priv); + + if (fop_with_fd) + ret = syncop_fgetxattr(this, (fd_t *)file_ptr, &dict, + "trusted.start_time", NULL, NULL); + else + ret = syncop_getxattr(this, (loc_t *)file_ptr, &dict, + "trusted.start_time", NULL, NULL); + if (ret < 0 || !dict) { + op_errno = ret; + gf_msg(this->name, GF_LOG_ERROR, -ret, 0, "Error getting xattr"); + goto out; + } + ret = dict_get_uint64(dict, "trusted.start_time", &start_time); + if (ret) { + op_errno = ret; + gf_msg(this->name, GF_LOG_ERROR, -ret, 0, "Error getting start time"); + goto out; + } + + com_period = priv->com_period; + if (fop_with_fd) + ret = syncop_fstat(this, (fd_t *)file_ptr, &stbuf, NULL, NULL); + else + ret = syncop_stat(this, (loc_t *)file_ptr, &stbuf, NULL, NULL); + if (ret) { + op_errno = ret; + gf_msg(this->name, GF_LOG_ERROR, -ret, 0, "Error getting file stat"); + goto out; + } + + ret = worm_get_state(this, fop_with_fd, file_ptr, &reten_state); + if (ret == -2) { + op_errno = ret; + gf_msg(this->name, GF_LOG_ERROR, -ret, 0, + "Error getting worm/retention state"); + goto out; + } + + now = gf_time(); + + if (ret == -1 && (now - start_time) >= com_period) { + if ((now - stbuf.ia_mtime) >= com_period) { + ret = worm_set_state(this, fop_with_fd, file_ptr, &reten_state, + &stbuf); + if (ret) { + op_errno = ret; + gf_msg(this->name, GF_LOG_ERROR, -ret, 0, + "Error setting worm/retention state"); + goto out; + } + goto out; + } else { + op_errno = 0; + goto out; + } + } else if (ret == -1 && (now - start_time) < com_period) { + op_errno = 0; + goto out; + } else if (reten_state.retain && ((now >= stbuf.ia_atime))) { + gf_worm_state_lookup(this, fop_with_fd, file_ptr, &reten_state, &stbuf); + } + if (reten_state.worm && !reten_state.retain && priv->worm_files_deletable && + op == GF_FOP_UNLINK) { + op_errno = 0; + goto out; + } + +out: + if (dict) + dict_unref(dict); + return op_errno; +} + +/*Function to check whether a file is independently WORMed (i.e., file level + * WORM is set on the file). */ +int32_t +is_wormfile(xlator_t *this, gf_boolean_t fop_with_fd, void *file_ptr) +{ + int ret = -1; + dict_t *dict = NULL; + + if (fop_with_fd) + ret = syncop_fgetxattr(this, (fd_t *)file_ptr, &dict, + "trusted.worm_file", NULL, NULL); + else + ret = syncop_getxattr(this, (loc_t *)file_ptr, &dict, + "trusted.worm_file", NULL, NULL); + if (dict) { + ret = 0; + dict_unref(dict); + } + return ret; +} diff --git a/xlators/features/read-only/src/worm-helper.h b/xlators/features/read-only/src/worm-helper.h new file mode 100644 index 00000000000..b42f8d2b40c --- /dev/null +++ b/xlators/features/read-only/src/worm-helper.h @@ -0,0 +1,44 @@ +/* + Copyright (c) 2016 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +gf_boolean_t +gf_worm_write_disabled(struct iatt *stbuf); + +int32_t +worm_init_state(xlator_t *this, gf_boolean_t fop_with_fd, void *file_ptr); + +int32_t +worm_set_state(xlator_t *this, gf_boolean_t fop_with_fd, void *file_ptr, + worm_reten_state_t *retention_state, struct iatt *stbuf); + +int32_t +worm_get_state(xlator_t *this, gf_boolean_t fop_with_fd, void *file_ptr, + worm_reten_state_t *reten_state); + +void +gf_worm_state_lookup(xlator_t *this, gf_boolean_t fop_with_fd, void *file_ptr, + worm_reten_state_t *reten_state, struct iatt *stbuf); + +void +gf_worm_serialize_state(worm_reten_state_t *reten_state, char *val); + +void +gf_worm_deserialize_state(char *val, worm_reten_state_t *reten_state); + +int32_t +gf_worm_set_xattr(xlator_t *this, worm_reten_state_t *reten_state, + gf_boolean_t fop_with_fd, void *file_ptr); + +int +gf_worm_state_transition(xlator_t *this, gf_boolean_t fop_with_fd, + void *file_ptr, glusterfs_fop_t op); + +int32_t +is_wormfile(xlator_t *this, gf_boolean_t fop_with_fd, void *file_ptr); diff --git a/xlators/features/read-only/src/worm.c b/xlators/features/read-only/src/worm.c index 16c3eb3daed..1cc5526d5cd 100644 --- a/xlators/features/read-only/src/worm.c +++ b/xlators/features/read-only/src/worm.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> + Copyright (c) 2008-2012, 2016 Red Hat, Inc. <http://www.redhat.com> This file is part of GlusterFS. This file is licensed to you under your choice of the GNU Lesser @@ -7,83 +7,716 @@ later), or the GNU General Public License, version 2 (GPLv2), in all cases as published by the Free Software Foundation. */ -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include "xlator.h" -#include "defaults.h" +#include <glusterfs/xlator.h> +#include <glusterfs/defaults.h> #include "read-only-common.h" +#include "read-only-mem-types.h" +#include "read-only.h" +#include <glusterfs/syncop.h> +#include "worm-helper.h" + +int32_t +mem_acct_init(xlator_t *this) +{ + int ret = -1; + + ret = xlator_mem_acct_init(this, gf_read_only_mt_end + 1); + if (ret) + gf_log(this->name, GF_LOG_ERROR, + "Memory accounting " + "initialization failed."); + + return ret; +} static int32_t -worm_open_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, - int32_t op_errno, fd_t *fd, dict_t *xdata) +worm_open(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags, + fd_t *fd, dict_t *xdata) { - STACK_UNWIND_STRICT (open, frame, op_ret, op_errno, fd, xdata); + if (is_readonly_or_worm_enabled(frame, this) && + (flags & (O_WRONLY | O_RDWR | O_APPEND | O_TRUNC))) { + STACK_UNWIND_STRICT(open, frame, -1, EROFS, NULL, NULL); return 0; + } + + STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->open, + loc, flags, fd, xdata); + return 0; } -int32_t -worm_open (call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags, - fd_t *fd, dict_t *xdata) +static int32_t +worm_link(call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc, + dict_t *xdata) { - if ((((flags & O_ACCMODE) == O_WRONLY) || - ((flags & O_ACCMODE) == O_RDWR)) && - !(flags & O_APPEND)) { - STACK_UNWIND_STRICT (open, frame, -1, EROFS, NULL, NULL); - return 0; + int op_errno = EROFS; + read_only_priv_t *priv = NULL; + + priv = this->private; + GF_ASSERT(priv); + if (is_readonly_or_worm_enabled(frame, this)) + goto out; + if (!priv->worm_file || (frame->root->pid < 0)) { + op_errno = 0; + goto out; + } + + gf_uuid_copy(oldloc->gfid, oldloc->inode->gfid); + if (is_wormfile(this, _gf_false, oldloc)) { + op_errno = 0; + goto out; + } + op_errno = gf_worm_state_transition(this, _gf_false, oldloc, GF_FOP_LINK); + +out: + if (op_errno) { + if (op_errno < 0) + op_errno = EROFS; + STACK_UNWIND_STRICT(link, frame, -1, op_errno, NULL, NULL, NULL, NULL, + NULL); + } else + STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->link, + oldloc, newloc, xdata); + return 0; +} + +static int32_t +worm_unlink(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags, + dict_t *xdata) +{ + int op_errno = EROFS; + read_only_priv_t *priv = NULL; + + priv = this->private; + GF_ASSERT(priv); + if (is_readonly_or_worm_enabled(frame, this)) { + goto out; + } + if (!priv->worm_file || (frame->root->pid < 0)) { + op_errno = 0; + goto out; + } + + gf_uuid_copy(loc->gfid, loc->inode->gfid); + if (is_wormfile(this, _gf_false, loc)) { + op_errno = 0; + goto out; + } + op_errno = gf_worm_state_transition(this, _gf_false, loc, GF_FOP_UNLINK); +out: + if (op_errno) { + if (op_errno < 0) + op_errno = EROFS; + STACK_UNWIND_STRICT(unlink, frame, -1, op_errno, NULL, NULL, NULL); + } else + STACK_WIND_TAIL(frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->unlink, loc, flags, xdata); + return 0; +} + +static int32_t +worm_rename(call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc, + dict_t *xdata) +{ + int op_errno = EROFS; + read_only_priv_t *priv = NULL; + + priv = this->private; + GF_ASSERT(priv); + if (is_readonly_or_worm_enabled(frame, this)) + goto out; + if (!priv->worm_file || (frame->root->pid < 0)) { + op_errno = 0; + goto out; + } + + gf_uuid_copy(oldloc->gfid, oldloc->inode->gfid); + if (is_wormfile(this, _gf_false, oldloc)) { + op_errno = 0; + goto check_newloc; + } + op_errno = gf_worm_state_transition(this, _gf_false, oldloc, GF_FOP_RENAME); + + if (op_errno == 0) { + check_newloc: + if (newloc->inode != NULL) { + gf_uuid_copy(newloc->gfid, newloc->inode->gfid); + if (is_wormfile(this, _gf_false, newloc)) { + op_errno = 0; + goto out; + } + op_errno = gf_worm_state_transition(this, _gf_false, newloc, + GF_FOP_RENAME); } + } - STACK_WIND (frame, worm_open_cbk, FIRST_CHILD(this), - FIRST_CHILD(this)->fops->open, loc, flags, fd, xdata); - return 0; +out: + if (op_errno) { + if (op_errno < 0) + op_errno = EROFS; + STACK_UNWIND_STRICT(rename, frame, -1, op_errno, NULL, NULL, NULL, NULL, + NULL, NULL); + } else + STACK_WIND_TAIL(frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->rename, oldloc, newloc, xdata); + return 0; } -int32_t -init (xlator_t *this) +static int32_t +worm_truncate(call_frame_t *frame, xlator_t *this, loc_t *loc, off_t offset, + dict_t *xdata) { - if (!this->children || this->children->next) { - gf_log (this->name, GF_LOG_ERROR, - "translator not configured with exactly one child"); - return -1; + int op_errno = EROFS; + read_only_priv_t *priv = NULL; + + priv = this->private; + GF_ASSERT(priv); + if (is_readonly_or_worm_enabled(frame, this)) + goto out; + if (!priv->worm_file || (frame->root->pid < 0)) { + op_errno = 0; + goto out; + } + + if (is_wormfile(this, _gf_false, loc)) { + op_errno = 0; + goto out; + } + op_errno = gf_worm_state_transition(this, _gf_false, loc, GF_FOP_TRUNCATE); + +out: + if (op_errno) { + if (op_errno < 0) + op_errno = EROFS; + STACK_UNWIND_STRICT(truncate, frame, -1, op_errno, NULL, NULL, NULL); + } else + STACK_WIND_TAIL(frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->truncate, loc, offset, xdata); + return 0; +} + +static int32_t +worm_ftruncate(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, + dict_t *xdata) +{ + int op_errno = EROFS; + read_only_priv_t *priv = NULL; + + priv = this->private; + GF_ASSERT(priv); + if (is_readonly_or_worm_enabled(frame, this)) + goto out; + if (!priv->worm_file || (frame->root->pid < 0)) { + op_errno = 0; + goto out; + } + + if (is_wormfile(this, _gf_true, fd)) { + op_errno = 0; + goto out; + } + op_errno = gf_worm_state_transition(this, _gf_true, fd, GF_FOP_FTRUNCATE); + +out: + if (op_errno) { + if (op_errno < 0) + op_errno = EROFS; + STACK_UNWIND_STRICT(ftruncate, frame, -1, op_errno, NULL, NULL, NULL); + } else + STACK_WIND_TAIL(frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->ftruncate, fd, offset, xdata); + return 0; +} + +static int32_t +worm_setattr(call_frame_t *frame, xlator_t *this, loc_t *loc, + struct iatt *stbuf, int32_t valid, dict_t *xdata) +{ + gf_boolean_t rd_only = _gf_false; + worm_reten_state_t reten_state = { + 0, + }; + struct iatt stpre = { + 0, + }; + read_only_priv_t *priv = NULL; + int op_errno = EROFS; + int ret = -1; + + priv = this->private; + GF_ASSERT(priv); + if (!priv->worm_file) { + op_errno = 0; + goto out; + } + + if (is_wormfile(this, _gf_false, loc)) { + op_errno = 0; + goto out; + } + if (valid & GF_SET_ATTR_MODE) { + rd_only = gf_worm_write_disabled(stbuf); + if (!rd_only) { + op_errno = 0; + goto out; } - if (!this->parents) { - gf_log (this->name, GF_LOG_WARNING, - "dangling volume. check volfile "); + ret = worm_set_state(this, _gf_false, loc, &reten_state, stbuf); + if (ret) { + gf_log(this->name, GF_LOG_ERROR, "Error setting worm state"); + goto out; + } + } else if (valid & GF_SET_ATTR_ATIME) { + ret = worm_get_state(this, _gf_false, loc, &reten_state); + if (ret) { + op_errno = 0; + goto out; } + if (reten_state.retain) { + ret = syncop_stat(this, loc, &stpre, NULL, NULL); + if (ret) + goto out; + if (reten_state.ret_mode == 0) { + if (stbuf->ia_atime < stpre.ia_mtime) { + gf_log(this->name, GF_LOG_ERROR, + "Cannot set atime less than " + "the mtime for a WORM-Retained " + "file"); + goto out; + } + } else { + if (stbuf->ia_atime < stpre.ia_atime) { + gf_log(this->name, GF_LOG_ERROR, + "Cannot decrease the atime of a" + " WORM-Retained file in " + "Enterprise mode"); + goto out; + } + } + reten_state.ret_period = reten_state.ret_period + stbuf->ia_atime - + stpre.ia_atime; + ret = gf_worm_set_xattr(this, &reten_state, _gf_false, loc); + if (ret) { + goto out; + } + stbuf->ia_mtime = stpre.ia_mtime; + } + } + op_errno = 0; - return 0; +out: + if (op_errno) + STACK_UNWIND_STRICT(setattr, frame, -1, EROFS, NULL, NULL, NULL); + else + STACK_WIND_TAIL(frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->setattr, loc, stbuf, valid, + xdata); + return 0; +} + +static int32_t +worm_fsetattr(call_frame_t *frame, xlator_t *this, fd_t *fd, struct iatt *stbuf, + int32_t valid, dict_t *xdata) +{ + gf_boolean_t rd_only = _gf_false; + worm_reten_state_t reten_state = { + 0, + }; + struct iatt stpre = { + 0, + }; + read_only_priv_t *priv = NULL; + int op_errno = EROFS; + int ret = -1; + + priv = this->private; + GF_ASSERT(priv); + if (!priv->worm_file) { + op_errno = 0; + goto out; + } + + if (is_wormfile(this, _gf_true, fd)) { + op_errno = 0; + goto out; + } + if (valid & GF_SET_ATTR_MODE) { + rd_only = gf_worm_write_disabled(stbuf); + if (!rd_only) { + op_errno = 0; + goto out; + } + + ret = worm_set_state(this, _gf_true, fd, &reten_state, stbuf); + if (ret) { + gf_log(this->name, GF_LOG_ERROR, "Error setting worm state"); + goto out; + } + } else if (valid & GF_SET_ATTR_ATIME) { + ret = worm_get_state(this, _gf_true, fd, &reten_state); + if (ret) { + op_errno = 0; + goto out; + } + if (reten_state.retain) { + ret = syncop_fstat(this, fd, &stpre, NULL, NULL); + if (ret) + goto out; + if (reten_state.ret_mode == 0) { + if (stbuf->ia_atime < stpre.ia_mtime) { + gf_log(this->name, GF_LOG_ERROR, + "Cannot set atime less than " + "the mtime for a WORM-Retained " + "file"); + goto out; + } + } else { + if (stbuf->ia_atime < stpre.ia_atime) { + gf_log(this->name, GF_LOG_ERROR, + "Cannot decrease the atime of a" + " WORM-Retained file in " + "Enterprise mode"); + goto out; + } + } + reten_state.ret_period = reten_state.ret_period + stbuf->ia_atime - + stpre.ia_atime; + ret = gf_worm_set_xattr(this, &reten_state, _gf_true, fd); + if (ret) { + goto out; + } + + stbuf->ia_mtime = stpre.ia_mtime; + } + } + op_errno = 0; + +out: + if (op_errno) + STACK_UNWIND_STRICT(fsetattr, frame, -1, op_errno, NULL, NULL, NULL); + else + STACK_WIND_TAIL(frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->fsetattr, fd, stbuf, valid, + xdata); + return 0; +} + +static int32_t +worm_writev(call_frame_t *frame, xlator_t *this, fd_t *fd, struct iovec *vector, + int32_t count, off_t offset, uint32_t flags, struct iobref *iobref, + dict_t *xdata) +{ + read_only_priv_t *priv = NULL; + int op_errno = EROFS; + + priv = this->private; + GF_ASSERT(priv); + if (!priv->worm_file || (frame->root->pid < 0)) { + op_errno = 0; + goto out; + } + if (is_wormfile(this, _gf_true, fd)) { + op_errno = 0; + goto out; + } + op_errno = gf_worm_state_transition(this, _gf_true, fd, GF_FOP_WRITE); + +out: + if (op_errno) { + if (op_errno < 0) + op_errno = EROFS; + STACK_UNWIND_STRICT(writev, frame, -1, op_errno, NULL, NULL, NULL); + } else + STACK_WIND_TAIL(frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->writev, fd, vector, count, + offset, flags, iobref, xdata); + return 0; +} + +static int32_t +worm_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 iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata) +{ + int ret = 0; + read_only_priv_t *priv = NULL; + // In case of an error exit because fd can be NULL and this would + // cause an segfault when performing fsetxattr . We explicitly + // unwind to avoid future problems + if (op_ret < 0) { + goto out; + } + + priv = this->private; + GF_ASSERT(priv); + if (priv->worm_file) { + ret = fd_ctx_set(fd, this, 1); + if (ret) { + gf_log(this->name, GF_LOG_ERROR, + "Failed to set the fd ctx " + "for gfid:%s . Worm feature may not work for the gfid", + uuid_utoa(inode->gfid)); + } + ret = worm_init_state(this, _gf_true, fd); + if (ret) { + gf_log(this->name, GF_LOG_ERROR, "Error initializing state"); + } + } + +out: + STACK_UNWIND_STRICT(create, frame, op_ret, op_errno, fd, inode, buf, + preparent, postparent, xdata); + return ret; +} + +static int32_t +worm_create(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags, + mode_t mode, mode_t umask, fd_t *fd, dict_t *xdata) +{ + STACK_WIND(frame, worm_create_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->create, loc, flags, mode, umask, fd, + xdata); + return 0; +} + +static void +set_reten_mode(read_only_priv_t *priv, char *reten_mode) +{ + if (strcmp(reten_mode, "relax") == 0) + priv->reten_mode = 0; + else + priv->reten_mode = 1; +} + +int32_t +init(xlator_t *this) +{ + int ret = -1; + read_only_priv_t *priv = NULL; + char *reten_mode = NULL; + + if (!this->children || this->children->next) { + gf_log(this->name, GF_LOG_ERROR, + "translator not configured with exactly one child"); + return -1; + } + + if (!this->parents) { + gf_log(this->name, GF_LOG_WARNING, "dangling volume. check volfile "); + } + + this->local_pool = mem_pool_new(read_only_priv_t, 64); + if (!this->local_pool) { + ret = -1; + gf_log(this->name, GF_LOG_ERROR, + "failed to create read_only_priv_t's memory pool"); + goto out; + } + + priv = mem_get0(this->local_pool); + if (!priv) { + gf_log(this->name, GF_LOG_ERROR, "Error allocating priv"); + goto out; + } + + this->private = priv; + + GF_OPTION_INIT("worm", priv->readonly_or_worm_enabled, bool, out); + GF_OPTION_INIT("worm-file-level", priv->worm_file, bool, out); + GF_OPTION_INIT("default-retention-period", priv->reten_period, int64, out); + GF_OPTION_INIT("auto-commit-period", priv->com_period, int64, out); + GF_OPTION_INIT("retention-mode", reten_mode, str, out); + set_reten_mode(priv, reten_mode); + GF_OPTION_INIT("worm-files-deletable", priv->worm_files_deletable, bool, + out); + + ret = 0; +out: + return ret; } +int +reconfigure(xlator_t *this, dict_t *options) +{ + read_only_priv_t *priv = NULL; + char *reten_mode = NULL; + int ret = -1; + + priv = this->private; + GF_ASSERT(priv); + + GF_OPTION_RECONF("worm", priv->readonly_or_worm_enabled, options, bool, + out); + GF_OPTION_RECONF("worm-file-level", priv->worm_file, options, bool, out); + GF_OPTION_RECONF("default-retention-period", priv->reten_period, options, + int64, out); + GF_OPTION_RECONF("retention-mode", reten_mode, options, str, out); + set_reten_mode(priv, reten_mode); + GF_OPTION_RECONF("auto-commit-period", priv->com_period, options, int64, + out); + GF_OPTION_RECONF("worm-files-deletable", priv->worm_files_deletable, + options, bool, out); + ret = 0; +out: + gf_log(this->name, GF_LOG_DEBUG, "returning %d", ret); + return ret; +} void -fini (xlator_t *this) +fini(xlator_t *this) { - return; + read_only_priv_t *priv = NULL; + + priv = this->private; + if (!priv) + goto out; + mem_put(priv); + this->private = NULL; + mem_pool_destroy(this->local_pool); + this->local_pool = NULL; +out: + return; } struct xlator_fops fops = { - .open = worm_open, - - .unlink = ro_unlink, - .rmdir = ro_rmdir, - .rename = ro_rename, - .truncate = ro_truncate, - .removexattr = ro_removexattr, - .fsyncdir = ro_fsyncdir, - .xattrop = ro_xattrop, - .inodelk = ro_inodelk, - .finodelk = ro_finodelk, - .entrylk = ro_entrylk, - .fentrylk = ro_fentrylk, - .lk = ro_lk, + .open = worm_open, + .writev = worm_writev, + .setattr = worm_setattr, + .fsetattr = worm_fsetattr, + .rename = worm_rename, + .link = worm_link, + .unlink = worm_unlink, + .truncate = worm_truncate, + .ftruncate = worm_ftruncate, + .create = worm_create, + + .rmdir = ro_rmdir, + .removexattr = ro_removexattr, + .fsyncdir = ro_fsyncdir, + .xattrop = ro_xattrop, + .inodelk = ro_inodelk, + .finodelk = ro_finodelk, + .entrylk = ro_entrylk, + .fentrylk = ro_fentrylk, + .lk = ro_lk, }; -struct xlator_cbks cbks; +int32_t +worm_release(xlator_t *this, fd_t *fd) +{ + dict_t *dict = NULL; + int ret = -1; + dict = dict_new(); + uint64_t value = 0; + loc_t loc = { + 0, + }; + read_only_priv_t *priv = NULL; + priv = this->private; + + if (priv->worm_file) { + if (!dict) { + gf_log(this->name, GF_LOG_ERROR, "Error creating the dict"); + goto out; + } + + ret = fd_ctx_get(fd, this, &value); + if (ret) { + gf_log(this->name, GF_LOG_DEBUG, "Failed to get the fd ctx"); + } + if (!value) { + goto out; + } + + ret = dict_set_int8(dict, "trusted.worm_file", 1); + if (ret) { + gf_log(this->name, GF_LOG_ERROR, + "Error in setting " + "the dict"); + goto out; + } + + loc.inode = inode_ref(fd->inode); + gf_uuid_copy(loc.gfid, fd->inode->gfid); + ret = syncop_setxattr(this, &loc, dict, 0, NULL, NULL); + if (ret) { + gf_log(this->name, GF_LOG_ERROR, "Error setting xattr"); + goto out; + } + + gf_worm_state_transition(this, _gf_false, &loc, GF_FOP_WRITE); + } + +out: + loc_wipe(&loc); + if (dict) + dict_unref(dict); + return 0; +} + +struct xlator_cbks cbks = { + .release = worm_release, +}; struct volume_options options[] = { - { .key = {NULL} }, + {.key = {"worm"}, + .type = GF_OPTION_TYPE_BOOL, + .default_value = "off", + /*.validate_fn = validate_boolean,*/ + .op_version = {2}, + .flags = OPT_FLAG_SETTABLE, + .description = "When \"on\", makes a volume get write once read many " + " feature. It is turned \"off\" by default."}, + {.key = {"worm-file-level"}, + .type = GF_OPTION_TYPE_BOOL, + .default_value = "off", + /*.validate_fn = validate_boolean,*/ + .op_version = {GD_OP_VERSION_3_8_0}, + .flags = OPT_FLAG_SETTABLE, + .description = "When \"on\", activates the file level worm. " + "It is turned \"off\" by default."}, + {.key = {"worm-files-deletable"}, + .type = GF_OPTION_TYPE_BOOL, + .default_value = "on", + /*.validate_fn = validate_boolean,*/ + .op_version = {GD_OP_VERSION_3_13_0}, + .flags = OPT_FLAG_SETTABLE, + .description = "When \"off\", doesn't allow the Worm files" + "to be deleted. It is turned \"on\" by default."}, + {.key = {"default-retention-period"}, + .type = GF_OPTION_TYPE_TIME, + .default_value = "120", + /*.validate_fn = validate_worm_period,*/ + .op_version = {GD_OP_VERSION_3_8_0}, + .flags = OPT_FLAG_SETTABLE, + .description = "The default retention period for the files."}, + {.key = {"retention-mode"}, + .type = GF_OPTION_TYPE_STR, + .default_value = "relax", + /*.validate_fn = validate_reten_mode,*/ + .op_version = {GD_OP_VERSION_3_8_0}, + .flags = OPT_FLAG_SETTABLE, + .description = "The mode of retention (relax/enterprise). " + "It is relax by default."}, + {.key = {"auto-commit-period"}, + .type = GF_OPTION_TYPE_TIME, + .default_value = "180", + /*.validate_fn = validate_worm_period,*/ + .op_version = {GD_OP_VERSION_3_8_0}, + .flags = OPT_FLAG_SETTABLE, + .description = "Auto commit period for the files."}, + {.key = {NULL}}, }; +xlator_api_t xlator_api = { + .init = init, + .fini = fini, + .reconfigure = reconfigure, + .mem_acct_init = mem_acct_init, + .op_version = {1}, /* Present from the initial version */ + .fops = &fops, + .cbks = &cbks, + .options = options, + .identifier = "worm", + .category = GF_TECH_PREVIEW, +}; |
