[tarantool-patches] [PATCH v1 1/1] box: support reload whole module
Kirill Shcherbatov
kshcherbatov at tarantool.org
Mon Jul 9 19:54:22 MSK 2018
@TarantoolBot document
Title: fixed module reload
There was a bug in tarantool documentation:
https://tarantool.io/en/doc/1.7/book/box/
box_schema/#lua-function.box.schema.func.reload
Now it is allowed to reload all functions in loadable
module via one method.
box.schema.func.reload("utils") -- ok since now
Global reload is still unsupported because it seems
to be useless.
box.schema.func.reload() -- invalid!
Closes #2946.
---
https://github.com/tarantool/tarantool/compare/kshch/gh-2946-module-reload
https://github.com/tarantool/tarantool/issues/2946
src/box/call.c | 37 ++++++++++++++++---------------------
src/box/call.h | 18 ++++++++++++++++++
src/box/func.c | 21 ++++++++++++++++++---
src/box/func.h | 15 +++++++++++++++
test/box/func_reload.result | 7 +++++++
test/box/func_reload.test.lua | 2 ++
6 files changed, 76 insertions(+), 24 deletions(-)
diff --git a/src/box/call.c b/src/box/call.c
index 438be19..dfe15dd 100644
--- a/src/box/call.c
+++ b/src/box/call.c
@@ -42,20 +42,8 @@
#include "rmean.h"
#include "small/obuf.h"
-/**
- * Find a function by name and check "EXECUTE" permissions.
- *
- * @param name function name
- * @param name_len length of @a name
- * @param[out] funcp function object
- * Sic: *pfunc == NULL means that perhaps the user has a global
- * "EXECUTE" privilege, so no specific grant to a function.
- *
- * @retval -1 on access denied
- * @retval 0 on success
- */
-static inline int
-access_check_func(const char *name, uint32_t name_len, struct func **funcp)
+int
+box_func_check_access(const char *name, uint32_t name_len, struct func **funcp)
{
struct func *func = func_by_name(name, name_len);
struct credentials *credentials = effective_user();
@@ -136,17 +124,24 @@ box_func_reload(const char *name)
{
size_t name_len = strlen(name);
struct func *func = NULL;
- if ((access_check_func(name, name_len, &func)) != 0)
+ if ((box_func_check_access(name, name_len, &func)) != 0)
return -1;
if (func == NULL) {
+ /* Try to interpret name as a module name. */
+ struct module *module;
+ if (module_reload(name, name + name_len, &module, true) == 0 &&
+ module != NULL)
+ return 0;
diag_set(ClientError, ER_NO_SUCH_FUNCTION, name);
return -1;
+ } else {
+ /* Such function exists. Try to reload it. */
+ if (func->def->language != FUNC_LANGUAGE_C)
+ return 0; /* Nothing to do */
+ if (func_reload(func) == 0)
+ return 0;
+ return -1;
}
- if (func->def->language != FUNC_LANGUAGE_C || func->func == NULL)
- return 0; /* Nothing to do */
- if (func_reload(func) == 0)
- return 0;
- return -1;
}
int
@@ -165,7 +160,7 @@ box_process_call(struct call_request *request, struct port *port)
* Sic: func == NULL means that perhaps the user has a global
* "EXECUTE" privilege, so no specific grant to a function.
*/
- if (access_check_func(name, name_len, &func) != 0)
+ if (box_func_check_access(name, name_len, &func) != 0)
return -1; /* permission denied */
/**
diff --git a/src/box/call.h b/src/box/call.h
index eabba69..55cf925 100644
--- a/src/box/call.h
+++ b/src/box/call.h
@@ -35,8 +35,11 @@
extern "C" {
#endif /* defined(__cplusplus) */
+#include <inttypes.h>
+
struct port;
struct call_request;
+struct func;
struct box_function_ctx {
struct port *port;
@@ -51,6 +54,21 @@ box_process_call(struct call_request *request, struct port *port);
int
box_process_eval(struct call_request *request, struct port *port);
+/**
+ * Find a function by name and check "EXECUTE" permissions.
+ *
+ * @param name function name
+ * @param name_len length of @a name
+ * @param[out] funcp function object
+ * Sic: *pfunc == NULL means that perhaps the user has a global
+ * "EXECUTE" privilege, so no specific grant to a function.
+ *
+ * @retval -1 on access denied.
+ * @retval 0 on success.
+ */
+int
+box_func_check_access(const char *name, uint32_t name_len, struct func **funcp);
+
#if defined(__cplusplus)
} /* extern "C" */
#endif /* defined(__cplusplus) */
diff --git a/src/box/func.c b/src/box/func.c
index dfbc5f3..dfab5d0 100644
--- a/src/box/func.c
+++ b/src/box/func.c
@@ -34,6 +34,7 @@
#include "lua/utils.h"
#include "error.h"
#include "diag.h"
+#include "call.h"
#include <dlfcn.h>
/**
@@ -302,7 +303,8 @@ module_sym(struct module *module, const char *name)
* Reload a dso.
*/
int
-module_reload(const char *package, const char *package_end, struct module **module)
+module_reload(const char *package, const char *package_end,
+ struct module **module, bool check_access)
{
struct module *old_module = module_cache_find(package, package_end);
if (old_module == NULL) {
@@ -318,7 +320,19 @@ module_reload(const char *package, const char *package_end, struct module **modu
struct func *func, *tmp_func;
rlist_foreach_entry_safe(func, &old_module->funcs, item, tmp_func) {
struct func_name name;
- func_split_name(func->def->name, &name);
+ const char *func_name = func->def->name;
+ func_split_name(func_name, &name);
+
+ /*
+ * Allow to reload only functions that belongs to
+ * current user. Skip other.
+ */
+ struct func *dummy;
+ if (check_access &&
+ box_func_check_access(func_name, strlen(func_name),
+ &dummy) != 0)
+ continue;
+
func->func = module_sym(new_module, name.sym);
if (func->func == NULL)
goto restore;
@@ -441,10 +455,11 @@ func_reload(struct func *func)
struct func_name name;
func_split_name(func->def->name, &name);
struct module *module = NULL;
- if (module_reload(name.package, name.package_end, &module) != 0) {
+ if (module_reload(name.package, name.package_end, &module, false) != 0) {
diag_log();
return -1;
}
+
return 0;
}
diff --git a/src/box/func.h b/src/box/func.h
index 0957546..168c2fc 100644
--- a/src/box/func.h
+++ b/src/box/func.h
@@ -116,6 +116,21 @@ func_call(struct func *func, box_function_ctx_t *ctx, const char *args,
int
func_reload(struct func *func);
+/**
+ * Reload dynamically loadable module.
+ *
+ * @param package name begin pointer.
+ * @param package_end name end pointer.
+ * @param[out] module a pointer to store module object on success.
+ * @param check_access do ACL checks if specified.
+ *
+ * @retval -1 on error
+ * @retval 0 on success
+ */
+int
+module_reload(const char *package, const char *package_end,
+ struct module **module, bool check_access);
+
#if defined(__cplusplus)
} /* extern "C" */
#endif /* defined(__cplusplus) */
diff --git a/test/box/func_reload.result b/test/box/func_reload.result
index 5aeb85c..9c05555 100644
--- a/test/box/func_reload.result
+++ b/test/box/func_reload.result
@@ -54,6 +54,10 @@ fio.symlink(reload1_path, reload_path)
box.schema.func.reload("reload.foo")
---
...
+box.schema.func.reload("reload")
+---
+- error: Function 'reload' does not exist
+...
-- test of usual case reload. No hanging calls
box.space.test:insert{0}
---
@@ -77,6 +81,9 @@ fio.symlink(reload2_path, reload_path)
box.schema.func.reload("reload.foo")
---
...
+box.schema.func.reload("reload")
+---
+...
c:call("reload.foo")
---
- []
diff --git a/test/box/func_reload.test.lua b/test/box/func_reload.test.lua
index dc56d84..5569dcd 100644
--- a/test/box/func_reload.test.lua
+++ b/test/box/func_reload.test.lua
@@ -21,6 +21,7 @@ fio.symlink(reload1_path, reload_path)
--check not fail on non-load func
box.schema.func.reload("reload.foo")
+box.schema.func.reload("reload")
-- test of usual case reload. No hanging calls
box.space.test:insert{0}
@@ -30,6 +31,7 @@ _ = fio.unlink(reload_path)
fio.symlink(reload2_path, reload_path)
box.schema.func.reload("reload.foo")
+box.schema.func.reload("reload")
c:call("reload.foo")
box.space.test:select{}
box.space.test:truncate()
--
2.7.4
More information about the Tarantool-patches
mailing list