diff options
Diffstat (limited to 'xlators/features/read-only/src/worm.c')
-rw-r--r-- | xlators/features/read-only/src/worm.c | 483 |
1 files changed, 454 insertions, 29 deletions
diff --git a/xlators/features/read-only/src/worm.c b/xlators/features/read-only/src/worm.c index f117e206285..2f35f1fc9f1 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 @@ -12,6 +12,9 @@ #include "read-only-common.h" #include "read-only-mem-types.h" #include "read-only.h" +#include "syncop.h" +#include "worm-helper.h" + int32_t mem_acct_init (xlator_t *this) @@ -26,35 +29,393 @@ mem_acct_init (xlator_t *this) 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) -{ - STACK_UNWIND_STRICT (open, frame, op_ret, op_errno, 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) { if (is_readonly_or_worm_enabled (this) && - ((((flags & O_ACCMODE) == O_WRONLY) || - ((flags & O_ACCMODE) == O_RDWR)) && - !(flags & O_APPEND))) { + (flags & (O_WRONLY | O_RDWR | O_APPEND))) { STACK_UNWIND_STRICT (open, frame, -1, EROFS, NULL, NULL); return 0; } - STACK_WIND (frame, worm_open_cbk, FIRST_CHILD(this), + STACK_WIND_TAIL (frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->open, loc, flags, fd, xdata); return 0; } + +int32_t +worm_link (call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc, + dict_t *xdata) +{ + int ret = -1; + int label = -1; + + if (is_readonly_or_worm_enabled (this)) + goto unwind; + gf_uuid_copy (oldloc->gfid, oldloc->inode->gfid); + if (is_wormfile (this, _gf_false, oldloc)) + goto wind; + label = state_transition (this, _gf_false, oldloc, GF_FOP_LINK, &ret); + if (label == 0) + goto wind; + if (label == 1) + goto unwind; + if (label == 2) + goto out; + +unwind: + STACK_UNWIND_STRICT (link, frame, -1, EROFS, NULL, NULL, NULL, NULL, + NULL); + ret = 0; + goto out; +wind: + STACK_WIND_TAIL (frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->link, + oldloc, newloc, xdata); + ret = 0; +out: + if (label == 2) + STACK_UNWIND_STRICT (link, frame, -1, ret, NULL, NULL, + NULL, NULL, NULL); + return ret; +} + + +int32_t +worm_unlink (call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags, + dict_t *xdata) +{ + int ret = -1; + int label = -1; + + if (is_readonly_or_worm_enabled (this)) + goto unwind; + gf_uuid_copy (loc->gfid, loc->inode->gfid); + if (is_wormfile (this, _gf_false, loc)) + goto wind; + label = state_transition (this, _gf_false, loc, GF_FOP_UNLINK, &ret); + if (label == 0) + goto wind; + if (label == 1) + goto unwind; + if (label == 2) + goto out; + +unwind: + STACK_UNWIND_STRICT (unlink, frame, -1, EROFS, NULL, NULL, NULL); + ret = 0; + goto out; +wind: + STACK_WIND_TAIL (frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->unlink, + loc, flags, xdata); + ret = 0; +out: + if (label == 2) + STACK_UNWIND_STRICT (unlink, frame, -1, ret, + NULL, NULL, NULL); + return ret; +} + + +int32_t +worm_rename (call_frame_t *frame, xlator_t *this, + loc_t *oldloc, loc_t *newloc, dict_t *xdata) +{ + int ret = -1; + int label = -1; + + if (is_readonly_or_worm_enabled (this)) + goto unwind; + gf_uuid_copy (oldloc->gfid, oldloc->inode->gfid); + if (is_wormfile (this, _gf_false, oldloc)) + goto wind; + label = state_transition (this, _gf_false, oldloc, GF_FOP_RENAME, + &ret); + if (label == 0) + goto wind; + if (label == 1) + goto unwind; + if (label == 2) + goto out; + +unwind: + STACK_UNWIND_STRICT (rename, frame, -1, EROFS, NULL, + NULL, NULL, NULL, NULL, NULL); + ret = 0; + goto out; +wind: + STACK_WIND_TAIL (frame, FIRST_CHILD (this), + FIRST_CHILD (this)->fops->rename, + oldloc, newloc, xdata); + ret = 0; +out: + if (label == 2) + STACK_UNWIND_STRICT (rename, frame, -1, ret, NULL, + NULL, NULL, NULL, NULL, NULL); + return ret; +} + + +int32_t +worm_truncate (call_frame_t *frame, xlator_t *this, loc_t *loc, off_t offset, + dict_t *xdata) +{ + int ret = -1; + int label = -1; + + if (is_readonly_or_worm_enabled (this)) + goto unwind; + if (is_wormfile (this, _gf_false, loc)) + goto wind; + label = state_transition (this, _gf_false, loc, GF_FOP_TRUNCATE, + &ret); + if (label == 0) + goto wind; + if (label == 1) + goto unwind; + if (label == 2) + goto out; + +unwind: + STACK_UNWIND_STRICT (truncate, frame, -1, EROFS, + NULL, NULL, NULL); + ret = 0; + goto out; + +wind: + STACK_WIND_TAIL (frame, + FIRST_CHILD (this), + FIRST_CHILD (this)->fops->truncate, + loc, offset, xdata); + ret = 0; +out: + if (label == 2) + STACK_UNWIND_STRICT (truncate, frame, -1, ret, + NULL, NULL, NULL); + return ret; +} + + +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,}; + int ret = -1; + + if (is_wormfile (this, _gf_false, loc)) + goto wind; + if (valid & GF_SET_ATTR_MODE) { + rd_only = is_write_disabled (stbuf); + if (!rd_only) + goto wind; + + 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) + goto wind; + 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 unwind; + } + } 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 unwind; + } + } + stbuf->ia_mtime = stpre.ia_mtime; + } + } + +wind: + STACK_WIND_TAIL (frame, FIRST_CHILD (this), + FIRST_CHILD (this)->fops->setattr, + loc, stbuf, valid, xdata); + ret = 0; + goto out; +unwind: + STACK_UNWIND_STRICT (setattr, frame, -1, EROFS, NULL, NULL, NULL); +out: + return ret; +} + + +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,}; + int ret = -1; + + if (is_wormfile (this, _gf_true, fd)) + goto wind; + if (valid & GF_SET_ATTR_MODE) { + rd_only = is_write_disabled (stbuf); + if (!rd_only) + goto wind; + + 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) + goto wind; + 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 unwind; + } + } 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 unwind; + } + } + stbuf->ia_mtime = stpre.ia_mtime; + } + } + +wind: + STACK_WIND_TAIL (frame, FIRST_CHILD (this), + FIRST_CHILD (this)->fops->fsetattr, + fd, stbuf, valid, xdata); + ret = 0; + goto out; +unwind: + STACK_UNWIND_STRICT (fsetattr, frame, -1, EROFS, NULL, NULL, NULL); +out: + return ret; +} + + +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) +{ + worm_reten_state_t reten_state = {0,}; + int ret = -1; + + if (is_readonly_or_worm_enabled (this)) + goto unwind; + if (is_wormfile (this, _gf_true, fd)) + goto wind; + ret = worm_get_state (this, _gf_true, fd, &reten_state); + if (!reten_state.worm) + goto wind; + +unwind: + STACK_UNWIND_STRICT (writev, frame, -1, EROFS, NULL, NULL, NULL); + goto out; + +wind: + STACK_WIND_TAIL (frame, + FIRST_CHILD (this), + FIRST_CHILD (this)->fops->writev, + fd, vector, count, offset, flags, + iobref, xdata); + gf_log (this->name, GF_LOG_INFO, "WORM writev"); + ret = 0; + +out: + return ret; +} + + +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) +{ + int ret = -1; + read_only_priv_t *priv = NULL; + dict_t *dict = NULL; + + STACK_WIND_TAIL (frame, FIRST_CHILD (this), + FIRST_CHILD(this)->fops->create, loc, flags, + mode, umask, fd, xdata); + priv = this->private; + GF_ASSERT (priv); + + if (priv->worm_file) { + dict = dict_new (); + if (!dict) { + gf_log (this->name, GF_LOG_ERROR, "Error creating the " + "dict"); + goto out; + } + GF_VALIDATE_OR_GOTO (this->name, dict, 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; + } + ret = syncop_fsetxattr (this, fd, dict, 0, NULL, NULL); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Error setting xattr"); + goto out; + } + ret = worm_init_state (this, _gf_true, fd); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Error initializing state"); + } + } + +out: + if (dict) + dict_destroy (dict); + return ret; +} + + int32_t init (xlator_t *this) { - int ret = -1; + int ret = -1; read_only_priv_t *priv = NULL; if (!this->children || this->children->next) { @@ -68,11 +429,34 @@ init (xlator_t *this) "dangling volume. check volfile "); } - priv = GF_CALLOC (1, sizeof (*priv), gf_read_only_mt_priv_t); - if (!priv) + 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; + } + + priv->reten_mode = mem_get0 (this->local_pool); + if (!priv->reten_mode) { + gf_log (this->name, GF_LOG_ERROR, "Error allocating " + "reten_mode"); goto out; + } - GF_OPTION_INIT ("worm", priv->readonly_or_worm_enabled, bool, out); + 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, + uint64, out); + GF_OPTION_INIT ("auto-commit-period", priv->com_period, uint64, out); + GF_OPTION_INIT ("retention-mode", priv->reten_mode, str, out); this->private = priv; ret = 0; @@ -80,25 +464,33 @@ out: return ret; } + int reconfigure (xlator_t *this, dict_t *options) { - read_only_priv_t *priv = NULL; + 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 ("worm", readonly_or_worm_enabled, options, bool, out); - - priv->readonly_or_worm_enabled = readonly_or_worm_enabled; + 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, uint64, out); + GF_OPTION_RECONF ("retention-mode", priv->reten_mode, options, str, + out); + GF_OPTION_RECONF ("auto-commit-period", priv->com_period, options, + uint64, out); ret = 0; out: gf_log (this->name, GF_LOG_DEBUG, "returning %d", ret); return ret; } + void fini (xlator_t *this) { @@ -106,21 +498,31 @@ fini (xlator_t *this) priv = this->private; if (!priv) - return; - + goto out; + if (priv->reten_mode != NULL) { + mem_put (priv->reten_mode); + priv->reten_mode = NULL; + } + mem_put (priv); this->private = NULL; - GF_FREE (priv); - + mem_pool_destroy (this->local_pool); +out: return; } + struct xlator_fops fops = { .open = worm_open, + .writev = worm_writev, + .setattr = worm_setattr, + .fsetattr = worm_fsetattr, + .rename = worm_rename, + .link = worm_link, + .unlink = worm_unlink, + .truncate = worm_truncate, + .create = worm_create, - .unlink = ro_unlink, .rmdir = ro_rmdir, - .rename = ro_rename, - .truncate = ro_truncate, .removexattr = ro_removexattr, .fsyncdir = ro_fsyncdir, .xattrop = ro_xattrop, @@ -131,8 +533,10 @@ struct xlator_fops fops = { .lk = ro_lk, }; + struct xlator_cbks cbks; + struct volume_options options[] = { { .key = {"worm"}, .type = GF_OPTION_TYPE_BOOL, @@ -140,5 +544,26 @@ struct volume_options options[] = { .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", + .description = "When \"on\", activates the file level worm. " + "It is turned \"off\" by default." + }, + { .key = {"default-retention-period"}, + .type = GF_OPTION_TYPE_TIME, + .default_value = "120", + .description = "The default retention period for the files." + }, + { .key = {"retention-mode"}, + .type = GF_OPTION_TYPE_STR, + .default_value = "relax", + .description = "The mode of retention (relax/enterprise). " + "It is relax by default." + }, + { .key = {"auto-commit-period"}, + .type = GF_OPTION_TYPE_TIME, + .default_value = "180", + .description = "Auto commit period for the files." + }, }; - |