/* Copyright (c) 2018 Red Hat, Inc. 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 "utime.h" #include "utime-helpers.h" #include "utime-messages.h" #include "utime-mem-types.h" #include int32_t gf_utime_invalidate(xlator_t *this, inode_t *inode) { return 0; } int32_t gf_utime_forget(xlator_t *this, inode_t *inode) { return 0; } int32_t gf_utime_client_destroy(xlator_t *this, client_t *client) { return 0; } void gf_utime_ictxmerge(xlator_t *this, fd_t *fd, inode_t *inode, inode_t *linked_inode) { return; } int32_t gf_utime_release(xlator_t *this, fd_t *fd) { return 0; } int32_t gf_utime_releasedir(xlator_t *this, fd_t *fd) { return 0; } int32_t gf_utime_client_disconnect(xlator_t *this, client_t *client) { return 0; } int32_t gf_utime_fdctx_to_dict(xlator_t *this, fd_t *fd, dict_t *dict) { return 0; } int32_t gf_utime_inode(xlator_t *this) { return 0; } int32_t gf_utime_inode_to_dict(xlator_t *this, dict_t *dict) { return 0; } int32_t gf_utime_history(xlator_t *this) { return 0; } int32_t gf_utime_fd(xlator_t *this) { return 0; } int32_t gf_utime_fd_to_dict(xlator_t *this, dict_t *dict) { return 0; } int32_t gf_utime_fdctx(xlator_t *this, fd_t *fd) { return 0; } int32_t gf_utime_inodectx(xlator_t *this, inode_t *ino) { return 0; } int32_t gf_utime_inodectx_to_dict(xlator_t *this, inode_t *ino, dict_t *dict) { return 0; } int32_t gf_utime_priv_to_dict(xlator_t *this, dict_t *dict, char *brickname) { return 0; } int32_t gf_utime_priv(xlator_t *this) { return 0; } int32_t mem_acct_init(xlator_t *this) { if (xlator_mem_acct_init(this, utime_mt_end + 1) != 0) { gf_msg(this->name, GF_LOG_ERROR, ENOMEM, UTIME_MSG_NO_MEMORY, "Memory accounting initialization failed."); return -1; } return 0; } int32_t gf_utime_set_mdata_setxattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int op_ret, int op_errno, dict_t *xdata) { call_stub_t *stub = frame->local; /* Don't fail lookup if mdata setxattr fails */ if (op_ret) { gf_msg(this->name, GF_LOG_ERROR, op_errno, UTIME_MSG_SET_MDATA_FAILED, "dict set of key for set-ctime-mdata failed"); } frame->local = NULL; call_resume(stub); STACK_DESTROY(frame->root); return 0; } int32_t gf_utime_set_mdata_lookup_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, inode_t *inode, struct iatt *stbuf, dict_t *xdata, struct iatt *postparent) { dict_t *dict = NULL; struct mdata_iatt *mdata = NULL; int ret = 0; loc_t loc = { 0, }; call_frame_t *new_frame = NULL; if (!op_ret && dict_get(xdata, GF_XATTR_MDATA_KEY) == NULL) { dict = dict_new(); if (!dict) { op_errno = ENOMEM; goto err; } mdata = GF_MALLOC(sizeof(struct mdata_iatt), gf_common_mt_char); if (mdata == NULL) { op_errno = ENOMEM; goto err; } iatt_to_mdata(mdata, stbuf); ret = dict_set_mdata(dict, CTIME_MDATA_XDATA_KEY, mdata, _gf_false); if (ret < 0) { gf_msg(this->name, GF_LOG_WARNING, ENOMEM, UTIME_MSG_NO_MEMORY, "dict set of key for set-ctime-mdata failed"); goto err; } new_frame = copy_frame(frame); if (!new_frame) { op_errno = ENOMEM; goto stub_err; } new_frame->local = fop_lookup_cbk_stub(frame, default_lookup_cbk, op_ret, op_errno, inode, stbuf, xdata, postparent); if (!new_frame->local) { gf_msg(this->name, GF_LOG_WARNING, ENOMEM, UTIME_MSG_NO_MEMORY, "lookup_cbk stub allocation failed"); op_errno = ENOMEM; STACK_DESTROY(new_frame->root); goto stub_err; } loc.inode = inode_ref(inode); gf_uuid_copy(loc.gfid, stbuf->ia_gfid); new_frame->root->uid = 0; new_frame->root->gid = 0; new_frame->root->pid = GF_CLIENT_PID_SET_UTIME; STACK_WIND(new_frame, gf_utime_set_mdata_setxattr_cbk, FIRST_CHILD(this), FIRST_CHILD(this)->fops->setxattr, &loc, dict, 0, NULL); dict_unref(dict); inode_unref(loc.inode); return 0; } STACK_UNWIND_STRICT(lookup, frame, op_ret, op_errno, inode, stbuf, xdata, postparent); return 0; err: if (mdata) { GF_FREE(mdata); } stub_err: if (dict) { dict_unref(dict); } STACK_UNWIND_STRICT(lookup, frame, -1, op_errno, NULL, NULL, NULL, NULL); return 0; } int gf_utime_lookup(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata) { int op_errno = -1; int ret = -1; VALIDATE_OR_GOTO(frame, err); VALIDATE_OR_GOTO(this, err); VALIDATE_OR_GOTO(loc, err); VALIDATE_OR_GOTO(loc->inode, err); xdata = xdata ? dict_ref(xdata) : dict_new(); if (!xdata) { op_errno = ENOMEM; goto err; } ret = dict_set_int8(xdata, GF_XATTR_MDATA_KEY, 1); if (ret < 0) { gf_msg(this->name, GF_LOG_WARNING, -ret, UTIME_MSG_DICT_SET_FAILED, "%s: Unable to set dict value for %s", loc->path, GF_XATTR_MDATA_KEY); op_errno = -ret; goto free_dict; } STACK_WIND(frame, gf_utime_set_mdata_lookup_cbk, FIRST_CHILD(this), FIRST_CHILD(this)->fops->lookup, loc, xdata); dict_unref(xdata); return 0; free_dict: dict_unref(xdata); err: STACK_UNWIND_STRICT(lookup, frame, -1, op_errno, NULL, NULL, NULL, NULL); return 0; } int32_t init(xlator_t *this) { utime_priv_t *utime = NULL; utime = GF_MALLOC(sizeof(*utime), utime_mt_utime_t); if (utime == NULL) { gf_msg(this->name, GF_LOG_ERROR, ENOMEM, UTIME_MSG_NO_MEMORY, "Failed to allocate private memory."); return -1; } memset(utime, 0, sizeof(*utime)); this->private = utime; GF_OPTION_INIT("noatime", utime->noatime, bool, err); return 0; err: return -1; } void fini(xlator_t *this) { utime_priv_t *utime = NULL; utime = this->private; GF_FREE(utime); return; } int32_t reconfigure(xlator_t *this, dict_t *options) { utime_priv_t *utime = this->private; GF_OPTION_RECONF("noatime", utime->noatime, options, bool, err); return 0; err: return -1; } int notify(xlator_t *this, int event, void *data, ...) { return default_notify(this, event, data); } struct xlator_fops fops = { .rename = gf_utime_rename, .mknod = gf_utime_mknod, .readv = gf_utime_readv, .fremovexattr = gf_utime_fremovexattr, .open = gf_utime_open, .create = gf_utime_create, .mkdir = gf_utime_mkdir, .writev = gf_utime_writev, .rmdir = gf_utime_rmdir, .fallocate = gf_utime_fallocate, .truncate = gf_utime_truncate, .symlink = gf_utime_symlink, .zerofill = gf_utime_zerofill, .link = gf_utime_link, .ftruncate = gf_utime_ftruncate, .unlink = gf_utime_unlink, .setattr = gf_utime_setattr, .fsetattr = gf_utime_fsetattr, .opendir = gf_utime_opendir, .removexattr = gf_utime_removexattr, .lookup = gf_utime_lookup, }; struct xlator_cbks cbks = { .invalidate = gf_utime_invalidate, .forget = gf_utime_forget, .client_destroy = gf_utime_client_destroy, .ictxmerge = gf_utime_ictxmerge, .release = gf_utime_release, .releasedir = gf_utime_releasedir, .client_disconnect = gf_utime_client_disconnect, }; struct xlator_dumpops dumpops = { .fdctx_to_dict = gf_utime_fdctx_to_dict, .inode = gf_utime_inode, .inode_to_dict = gf_utime_inode_to_dict, .history = gf_utime_history, .fd = gf_utime_fd, .fd_to_dict = gf_utime_fd_to_dict, .fdctx = gf_utime_fdctx, .inodectx = gf_utime_inodectx, .inodectx_to_dict = gf_utime_inodectx_to_dict, .priv_to_dict = gf_utime_priv_to_dict, .priv = gf_utime_priv, }; struct volume_options options[] = { {.key = {"noatime"}, .type = GF_OPTION_TYPE_BOOL, .default_value = "on", .op_version = {GD_OP_VERSION_5_0}, .flags = OPT_FLAG_SETTABLE | OPT_FLAG_CLIENT_OPT | OPT_FLAG_DOC, .tags = {"ctime"}, .description = "Enable/Disable atime updation when ctime feature is " "enabled. When noatime is on, atime is not updated with " "ctime feature enabled and vice versa."}, {.key = {NULL}}}; xlator_api_t xlator_api = { .init = init, .fini = fini, .notify = notify, .reconfigure = reconfigure, .mem_acct_init = mem_acct_init, .op_version = {GD_OP_VERSION_5_0}, .dumpops = &dumpops, .fops = &fops, .cbks = &cbks, .options = options, .identifier = "utime", .category = GF_MAINTAINED, };