Discussion:
[PATCH v1 1/2] xen/kexec: Find out whether an kexec type is loaded.
Konrad Rzeszutek Wilk
2016-11-14 22:12:52 UTC
Permalink
The tools that use kexec are asynchronous in nature and do
not keep state changes. As such provide an hypercall to find
out whether an image has been loaded for either type.

Note: No need to modify XSM as it has one size fits all
check and does not check for subcommands.

Signed-off-by: Konrad Rzeszutek Wilk <***@oracle.com>
---
v0: Internal version.
v1: Dropped Reviewed-by, posting on xen-devel.

CC: Elena Ufimtseva <***@oracle.com>
CC: Daniel Kiper <***@oracle.com>
---
tools/libxc/include/xenctrl.h | 8 ++++++++
tools/libxc/xc_kexec.c | 27 +++++++++++++++++++++++++++
xen/common/kexec.c | 25 +++++++++++++++++++++++++
xen/include/public/kexec.h | 11 +++++++++++
4 files changed, 71 insertions(+)

diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index 2c83544..aa5d798 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -2574,6 +2574,14 @@ int xc_kexec_load(xc_interface *xch, uint8_t type, uint16_t arch,
*/
int xc_kexec_unload(xc_interface *xch, int type);

+/*
+ * Find out whether the image has been succesfully loaded.
+ *
+ * The can be either KEXEC_TYPE_DEFAULT or KEXEC_TYPE_CRASH.
+ * If zero is returned that means the image is loaded for the type.
+ */
+int xc_kexec_status(xc_interface *xch, int type);
+
typedef xenpf_resource_entry_t xc_resource_entry_t;

/*
diff --git a/tools/libxc/xc_kexec.c b/tools/libxc/xc_kexec.c
index 1cceb5d..95d36ff 100644
--- a/tools/libxc/xc_kexec.c
+++ b/tools/libxc/xc_kexec.c
@@ -126,3 +126,30 @@ out:

return ret;
}
+
+int xc_kexec_status(xc_interface *xch, int type)
+{
+ DECLARE_HYPERCALL;
+ DECLARE_HYPERCALL_BUFFER(xen_kexec_status_t, status);
+ int ret = -1;
+
+ status = xc_hypercall_buffer_alloc(xch, status, sizeof(*status));
+ if ( status == NULL )
+ {
+ PERROR("Count not alloc buffer for kexec status hypercall");
+ goto out;
+ }
+
+ status->type = type;
+
+ hypercall.op = __HYPERVISOR_kexec_op;
+ hypercall.arg[0] = KEXEC_CMD_kexec_status;
+ hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(status);
+
+ ret = do_xen_hypercall(xch, &hypercall);
+
+out:
+ xc_hypercall_buffer_free(xch, status);
+
+ return ret;
+}
diff --git a/xen/common/kexec.c b/xen/common/kexec.c
index c83d48f..1148f85 100644
--- a/xen/common/kexec.c
+++ b/xen/common/kexec.c
@@ -1169,6 +1169,28 @@ static int kexec_unload(XEN_GUEST_HANDLE_PARAM(void) uarg)
return kexec_do_unload(&unload);
}

+static int kexec_status(XEN_GUEST_HANDLE_PARAM(void) uarg)
+{
+ xen_kexec_status_t status;
+ int base, bit, pos;
+
+ if ( unlikely(copy_from_guest(&status, uarg, 1)) )
+ return -EFAULT;
+
+ if ( test_bit(KEXEC_FLAG_IN_PROGRESS, &kexec_flags) )
+ return -EBUSY;
+
+ if ( kexec_load_get_bits(status.type, &base, &bit) )
+ return -EINVAL;
+
+ pos = (test_bit(bit, &kexec_flags) != 0);
+
+ if ( !test_bit(base + pos, &kexec_flags) )
+ return -ENOENT;
+
+ return 0;
+}
+
static int do_kexec_op_internal(unsigned long op,
XEN_GUEST_HANDLE_PARAM(void) uarg,
bool_t compat)
@@ -1208,6 +1230,9 @@ static int do_kexec_op_internal(unsigned long op,
case KEXEC_CMD_kexec_unload:
ret = kexec_unload(uarg);
break;
+ case KEXEC_CMD_kexec_status:
+ ret = kexec_status(uarg);
+ break;
}

return ret;
diff --git a/xen/include/public/kexec.h b/xen/include/public/kexec.h
index a6a0a88..29dcb5d 100644
--- a/xen/include/public/kexec.h
+++ b/xen/include/public/kexec.h
@@ -227,6 +227,17 @@ typedef struct xen_kexec_unload {
} xen_kexec_unload_t;
DEFINE_XEN_GUEST_HANDLE(xen_kexec_unload_t);

+/*
+ * Figure out whether we have an image loaded. An return value of
+ * zero indicates success while XEN_ENODEV implies no image loaded.
+ *
+ * Type must be one of KEXEC_TYPE_DEFAULT or KEXEC_TYPE_CRASH.
+ */
+#define KEXEC_CMD_kexec_status 6
+typedef struct xen_kexec_status {
+ uint8_t type;
+} xen_kexec_status_t;
+DEFINE_XEN_GUEST_HANDLE(xen_kexec_status_t);
#else /* __XEN_INTERFACE_VERSION__ < 0x00040400 */

#define KEXEC_CMD_kexec_load KEXEC_CMD_kexec_load_v1
--
2.5.5
Konrad Rzeszutek Wilk
2016-11-14 22:12:53 UTC
Permalink
Instead of the scripts having to poke at various fields we can
provide that functionality via the -S parameter.

Returns 0 if the payload is loaded. Can be used in combination
with -l or -p to get the state of the proper kexec image.

Signed-off-by: Konrad Rzeszutek Wilk <***@oracle.com>
---
v0: First version (internal product).
v1: Posted on kexec mailing list. Changed -s to -S

CC: ***@lists.infradead.org
CC: xen-***@lists.xenproject.org
CC: Daniel Kiper <***@oracle.com>
---
kexec/kexec-xen.c | 20 ++++++++++++++++++
kexec/kexec.8 | 5 +++++
kexec/kexec.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
kexec/kexec.h | 5 ++++-
4 files changed, 85 insertions(+), 6 deletions(-)

diff --git a/kexec/kexec-xen.c b/kexec/kexec-xen.c
index 24a4191..5a1e9d2 100644
--- a/kexec/kexec-xen.c
+++ b/kexec/kexec-xen.c
@@ -105,6 +105,26 @@ int xen_kexec_unload(uint64_t kexec_flags)
return ret;
}

+int xen_kexec_status(uint64_t kexec_flags)
+{
+ xc_interface *xch;
+ uint8_t type;
+ int ret;
+
+ xch = xc_interface_open(NULL, NULL, 0);
+ if (!xch)
+ return -1;
+
+ type = (kexec_flags & KEXEC_ON_CRASH) ? KEXEC_TYPE_CRASH
+ : KEXEC_TYPE_DEFAULT;
+
+ ret = xc_kexec_status(xch, type);
+
+ xc_interface_close(xch);
+
+ return ret;
+}
+
void xen_kexec_exec(void)
{
xc_interface *xch;
diff --git a/kexec/kexec.8 b/kexec/kexec.8
index 4d0c1d1..02f4ccf 100644
--- a/kexec/kexec.8
+++ b/kexec/kexec.8
@@ -107,6 +107,11 @@ command:
.B \-d\ (\-\-debug)
Enable debugging messages.
.TP
+.B \-D\ (\-\-status)
+Return 0 if the type (by default crash) is loaded. Can be used in conjuction
+with -l or -p to toggle the type. Note it will
+.BR not\ load\ the\ kernel.
+.TP
.B \-e\ (\-\-exec)
Run the currently loaded kernel. Note that it will reboot into the loaded kernel without calling shutdown(8).
.TP
diff --git a/kexec/kexec.c b/kexec/kexec.c
index 500e5a9..bc72688 100644
--- a/kexec/kexec.c
+++ b/kexec/kexec.c
@@ -855,6 +855,32 @@ static int k_unload (unsigned long kexec_flags)
return result;
}

+static int kexec_loaded(void);
+static int __kexec_loaded(const char *f);
+
+static int k_status(unsigned long kexec_flags)
+{
+ int result;
+ long native_arch;
+
+ /* set the arch */
+ native_arch = physical_arch();
+ if (native_arch < 0) {
+ return -1;
+ }
+ kexec_flags |= native_arch;
+
+ if (xen_present())
+ result = xen_kexec_status(kexec_flags);
+ else {
+ if (kexec_flags & KEXEC_ON_CRASH)
+ result = __kexec_loaded("/sys/kernel/kexec_crash_loaded");
+ else
+ result = kexec_loaded();
+ }
+ return result;
+}
+
/*
* Start a reboot.
*/
@@ -890,8 +916,6 @@ static int my_exec(void)
return -1;
}

-static int kexec_loaded(void);
-
static int load_jump_back_helper_image(unsigned long kexec_flags, void *entry)
{
int result;
@@ -970,6 +994,7 @@ void usage(void)
" to original kernel.\n"
" -s, --kexec-file-syscall Use file based syscall for kexec operation\n"
" -d, --debug Enable debugging to help spot a failure.\n"
+ " -S, --status Return 0 if the type (by default crash) is loaded.\n"
"\n"
"Supported kernel file types and options: \n");
for (i = 0; i < file_types; i++) {
@@ -981,7 +1006,7 @@ void usage(void)
printf("\n");
}

-static int kexec_loaded(void)
+static int __kexec_loaded(const char *file)
{
long ret = -1;
FILE *fp;
@@ -992,7 +1017,7 @@ static int kexec_loaded(void)
if (xen_present())
return 1;

- fp = fopen("/sys/kernel/kexec_loaded", "r");
+ fp = fopen(file, "r");
if (fp == NULL)
return -1;

@@ -1015,6 +1040,12 @@ static int kexec_loaded(void)
return (int)ret;
}

+static int kexec_loaded(void)
+{
+ return __kexec_loaded("/sys/kernel/kexec_loaded");
+}
+
+
/*
* Remove parameter from a kernel command line. Helper function by get_command_line().
*/
@@ -1204,6 +1235,7 @@ int main(int argc, char *argv[])
int do_unload = 0;
int do_reuse_initrd = 0;
int do_kexec_file_syscall = 0;
+ int do_status = 0;
void *entry = 0;
char *type = 0;
char *endptr;
@@ -1345,6 +1377,9 @@ int main(int argc, char *argv[])
case OPT_KEXEC_FILE_SYSCALL:
/* We already parsed it. Nothing to do. */
break;
+ case OPT_STATUS:
+ do_status = 1;
+ break;
default:
break;
}
@@ -1355,6 +1390,20 @@ int main(int argc, char *argv[])
if (skip_sync)
do_sync = 0;

+ if (do_status) {
+ if (kexec_flags == 0)
+ kexec_flags = KEXEC_ON_CRASH;
+ do_load = 0;
+ do_reuse_initrd = 0;
+ do_unload = 0;
+ do_load = 0;
+ do_shutdown = 0;
+ do_sync = 0;
+ do_ifdown = 0;
+ do_exec = 0;
+ do_load_jump_back_helper = 0;
+ }
+
if (do_load && (kexec_flags & KEXEC_ON_CRASH) &&
!is_crashkernel_mem_reserved()) {
die("Memory for crashkernel is not reserved\n"
@@ -1392,7 +1441,9 @@ int main(int argc, char *argv[])
check_reuse_initrd();
arch_reuse_initrd();
}
-
+ if (do_status) {
+ result = k_status(kexec_flags);
+ }
if (do_unload) {
if (do_kexec_file_syscall)
result = kexec_file_unload(kexec_file_flags);
diff --git a/kexec/kexec.h b/kexec/kexec.h
index 9194f1c..2b06f59 100644
--- a/kexec/kexec.h
+++ b/kexec/kexec.h
@@ -219,6 +219,7 @@ extern int file_types;
#define OPT_TYPE 't'
#define OPT_PANIC 'p'
#define OPT_KEXEC_FILE_SYSCALL 's'
+#define OPT_STATUS 'S'
#define OPT_MEM_MIN 256
#define OPT_MEM_MAX 257
#define OPT_REUSE_INITRD 258
@@ -245,8 +246,9 @@ extern int file_types;
{ "reuseinitrd", 0, 0, OPT_REUSE_INITRD }, \
{ "kexec-file-syscall", 0, 0, OPT_KEXEC_FILE_SYSCALL }, \
{ "debug", 0, 0, OPT_DEBUG }, \
+ { "status", 0, 0, OPT_STATUS }, \

-#define KEXEC_OPT_STR "h?vdfxyluet:ps"
+#define KEXEC_OPT_STR "h?vdfxyluet:psS"

extern void dbgprint_mem_range(const char *prefix, struct memory_range *mr, int nr_mr);
extern void die(const char *fmt, ...)
@@ -311,5 +313,6 @@ int xen_present(void);
int xen_kexec_load(struct kexec_info *info);
int xen_kexec_unload(uint64_t kexec_flags);
void xen_kexec_exec(void);
+int xen_kexec_status(uint64_t kexec_flags);

#endif /* KEXEC_H */
--
2.5.5
Pratyush Anand
2016-11-15 04:44:13 UTC
Permalink
Post by Konrad Rzeszutek Wilk
Instead of the scripts having to poke at various fields we can
provide that functionality via the -S parameter.
Returns 0 if the payload is loaded. Can be used in combination
with -l or -p to get the state of the proper kexec image.
---
v0: First version (internal product).
v1: Posted on kexec mailing list. Changed -s to -S
---
kexec/kexec-xen.c | 20 ++++++++++++++++++
kexec/kexec.8 | 5 +++++
kexec/kexec.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
kexec/kexec.h | 5 ++++-
4 files changed, 85 insertions(+), 6 deletions(-)
diff --git a/kexec/kexec-xen.c b/kexec/kexec-xen.c
index 24a4191..5a1e9d2 100644
--- a/kexec/kexec-xen.c
+++ b/kexec/kexec-xen.c
@@ -105,6 +105,26 @@ int xen_kexec_unload(uint64_t kexec_flags)
return ret;
}
+int xen_kexec_status(uint64_t kexec_flags)
+{
+ xc_interface *xch;
+ uint8_t type;
+ int ret;
+
+ xch = xc_interface_open(NULL, NULL, 0);
+ if (!xch)
+ return -1;
+
+ type = (kexec_flags & KEXEC_ON_CRASH) ? KEXEC_TYPE_CRASH
+ : KEXEC_TYPE_DEFAULT;
+
+ ret = xc_kexec_status(xch, type);
+
+ xc_interface_close(xch);
+
+ return ret;
+}
+
void xen_kexec_exec(void)
{
xc_interface *xch;
diff --git a/kexec/kexec.8 b/kexec/kexec.8
index 4d0c1d1..02f4ccf 100644
--- a/kexec/kexec.8
+++ b/kexec/kexec.8
.B \-d\ (\-\-debug)
Enable debugging messages.
.TP
+.B \-D\ (\-\-status)
+Return 0 if the type (by default crash) is loaded. Can be used in conjuction
+with -l or -p to toggle the type. Note it will
+.BR not\ load\ the\ kernel.
Better to specify that it will supersede all other options and will
neither load nor unload the kernel.
Post by Konrad Rzeszutek Wilk
+.TP
.B \-e\ (\-\-exec)
Run the currently loaded kernel. Note that it will reboot into the loaded kernel without calling shutdown(8).
.TP
diff --git a/kexec/kexec.c b/kexec/kexec.c
index 500e5a9..bc72688 100644
--- a/kexec/kexec.c
+++ b/kexec/kexec.c
@@ -855,6 +855,32 @@ static int k_unload (unsigned long kexec_flags)
return result;
}
+static int kexec_loaded(void);
+static int __kexec_loaded(const char *f);
+
Why not to define k_status below kexec_loaded() so that you do not need
above prototypes.
Post by Konrad Rzeszutek Wilk
+static int k_status(unsigned long kexec_flags)
+{
+ int result;
+ long native_arch;
+
+ /* set the arch */
+ native_arch = physical_arch();
+ if (native_arch < 0) {
+ return -1;
+ }
+ kexec_flags |= native_arch;
+
+ if (xen_present())
+ result = xen_kexec_status(kexec_flags);
+ else {
+ if (kexec_flags & KEXEC_ON_CRASH)
+ result = __kexec_loaded("/sys/kernel/kexec_crash_loaded");
+ else
+ result = kexec_loaded();
+ }
+ return result;
+}
+
/*
* Start a reboot.
*/
@@ -890,8 +916,6 @@ static int my_exec(void)
return -1;
}
-static int kexec_loaded(void);
-
static int load_jump_back_helper_image(unsigned long kexec_flags, void *entry)
{
int result;
@@ -970,6 +994,7 @@ void usage(void)
" to original kernel.\n"
" -s, --kexec-file-syscall Use file based syscall for kexec operation\n"
" -d, --debug Enable debugging to help spot a failure.\n"
+ " -S, --status Return 0 if the type (by default crash) is loaded.\n"
"\n"
"Supported kernel file types and options: \n");
for (i = 0; i < file_types; i++) {
@@ -981,7 +1006,7 @@ void usage(void)
printf("\n");
}
-static int kexec_loaded(void)
+static int __kexec_loaded(const char *file)
{
long ret = -1;
FILE *fp;
@@ -992,7 +1017,7 @@ static int kexec_loaded(void)
if (xen_present())
return 1;
- fp = fopen("/sys/kernel/kexec_loaded", "r");
+ fp = fopen(file, "r");
if (fp == NULL)
return -1;
@@ -1015,6 +1040,12 @@ static int kexec_loaded(void)
return (int)ret;
}
+static int kexec_loaded(void)
+{
+ return __kexec_loaded("/sys/kernel/kexec_loaded");
+}
Since kexec_loaded() has been called at only one place, better to remove
above function and use __kexec_loaded() directly. And then you might not
need to rename kexec_loaded() to __kexec_loaded() as well.
Post by Konrad Rzeszutek Wilk
+
+
/*
* Remove parameter from a kernel command line. Helper function by get_command_line().
*/
@@ -1204,6 +1235,7 @@ int main(int argc, char *argv[])
int do_unload = 0;
int do_reuse_initrd = 0;
int do_kexec_file_syscall = 0;
+ int do_status = 0;
void *entry = 0;
char *type = 0;
char *endptr;
@@ -1345,6 +1377,9 @@ int main(int argc, char *argv[])
/* We already parsed it. Nothing to do. */
break;
+ do_status = 1;
why not to call k_status() here and then return so that you get rid of all
other changes in this function?
Post by Konrad Rzeszutek Wilk
+ break;
break;
}
@@ -1355,6 +1390,20 @@ int main(int argc, char *argv[])
if (skip_sync)
do_sync = 0;
+ if (do_status) {
+ if (kexec_flags == 0)
+ kexec_flags = KEXEC_ON_CRASH;
+ do_load = 0;
+ do_reuse_initrd = 0;
+ do_unload = 0;
+ do_load = 0;
+ do_shutdown = 0;
+ do_sync = 0;
+ do_ifdown = 0;
+ do_exec = 0;
+ do_load_jump_back_helper = 0;
+ }
+
if (do_load && (kexec_flags & KEXEC_ON_CRASH) &&
!is_crashkernel_mem_reserved()) {
die("Memory for crashkernel is not reserved\n"
@@ -1392,7 +1441,9 @@ int main(int argc, char *argv[])
check_reuse_initrd();
arch_reuse_initrd();
}
-
+ if (do_status) {
+ result = k_status(kexec_flags);
+ }
if (do_unload) {
if (do_kexec_file_syscall)
result = kexec_file_unload(kexec_file_flags);
diff --git a/kexec/kexec.h b/kexec/kexec.h
index 9194f1c..2b06f59 100644
--- a/kexec/kexec.h
+++ b/kexec/kexec.h
@@ -219,6 +219,7 @@ extern int file_types;
#define OPT_TYPE 't'
#define OPT_PANIC 'p'
#define OPT_KEXEC_FILE_SYSCALL 's'
+#define OPT_STATUS 'S'
#define OPT_MEM_MIN 256
#define OPT_MEM_MAX 257
#define OPT_REUSE_INITRD 258
@@ -245,8 +246,9 @@ extern int file_types;
{ "reuseinitrd", 0, 0, OPT_REUSE_INITRD }, \
{ "kexec-file-syscall", 0, 0, OPT_KEXEC_FILE_SYSCALL }, \
{ "debug", 0, 0, OPT_DEBUG }, \
+ { "status", 0, 0, OPT_STATUS }, \
-#define KEXEC_OPT_STR "h?vdfxyluet:ps"
+#define KEXEC_OPT_STR "h?vdfxyluet:psS"
extern void dbgprint_mem_range(const char *prefix, struct memory_range *mr, int nr_mr);
extern void die(const char *fmt, ...)
@@ -311,5 +313,6 @@ int xen_present(void);
int xen_kexec_load(struct kexec_info *info);
int xen_kexec_unload(uint64_t kexec_flags);
void xen_kexec_exec(void);
+int xen_kexec_status(uint64_t kexec_flags);
#endif /* KEXEC_H */
~Pratyush
Simon Horman
2016-11-16 12:50:11 UTC
Permalink
Post by Konrad Rzeszutek Wilk
Instead of the scripts having to poke at various fields we can
provide that functionality via the -S parameter.
Returns 0 if the payload is loaded. Can be used in combination
with -l or -p to get the state of the proper kexec image.
---
v0: First version (internal product).
v1: Posted on kexec mailing list. Changed -s to -S
---
kexec/kexec-xen.c | 20 ++++++++++++++++++
kexec/kexec.8 | 5 +++++
kexec/kexec.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
kexec/kexec.h | 5 ++++-
4 files changed, 85 insertions(+), 6 deletions(-)
diff --git a/kexec/kexec-xen.c b/kexec/kexec-xen.c
index 24a4191..5a1e9d2 100644
--- a/kexec/kexec-xen.c
+++ b/kexec/kexec-xen.c
@@ -105,6 +105,26 @@ int xen_kexec_unload(uint64_t kexec_flags)
return ret;
}
+int xen_kexec_status(uint64_t kexec_flags)
+{
+ xc_interface *xch;
+ uint8_t type;
+ int ret;
+
+ xch = xc_interface_open(NULL, NULL, 0);
+ if (!xch)
+ return -1;
+
+ type = (kexec_flags & KEXEC_ON_CRASH) ? KEXEC_TYPE_CRASH
+ : KEXEC_TYPE_DEFAULT;
+
+ ret = xc_kexec_status(xch, type);
+
+ xc_interface_close(xch);
+
+ return ret;
+}
+
void xen_kexec_exec(void)
{
xc_interface *xch;
diff --git a/kexec/kexec.8 b/kexec/kexec.8
index 4d0c1d1..02f4ccf 100644
--- a/kexec/kexec.8
+++ b/kexec/kexec.8
.B \-d\ (\-\-debug)
Enable debugging messages.
.TP
+.B \-D\ (\-\-status)
+Return 0 if the type (by default crash) is loaded. Can be used in conjuction
+with -l or -p to toggle the type. Note it will
Is there a mnemonic to map -D to --status?
If not perhaps it would be best to drop the short option.
Post by Konrad Rzeszutek Wilk
+.BR not\ load\ the\ kernel.
+.TP
.B \-e\ (\-\-exec)
Run the currently loaded kernel. Note that it will reboot into the loaded kernel without calling shutdown(8).
.TP
diff --git a/kexec/kexec.c b/kexec/kexec.c
index 500e5a9..bc72688 100644
--- a/kexec/kexec.c
+++ b/kexec/kexec.c
@@ -855,6 +855,32 @@ static int k_unload (unsigned long kexec_flags)
return result;
}
+static int kexec_loaded(void);
+static int __kexec_loaded(const char *f);
I wonder if we could shuffle the location of functions
in this file to avoid the need to forward declarations all together.
Post by Konrad Rzeszutek Wilk
+
+static int k_status(unsigned long kexec_flags)
+{
+ int result;
+ long native_arch;
+
+ /* set the arch */
+ native_arch = physical_arch();
+ if (native_arch < 0) {
+ return -1;
+ }
+ kexec_flags |= native_arch;
+
+ if (xen_present())
+ result = xen_kexec_status(kexec_flags);
+ else {
+ if (kexec_flags & KEXEC_ON_CRASH)
+ result = __kexec_loaded("/sys/kernel/kexec_crash_loaded");
+ else
+ result = kexec_loaded();
+ }
+ return result;
+}
+
/*
* Start a reboot.
*/
@@ -890,8 +916,6 @@ static int my_exec(void)
return -1;
}
-static int kexec_loaded(void);
-
static int load_jump_back_helper_image(unsigned long kexec_flags, void *entry)
{
int result;
@@ -970,6 +994,7 @@ void usage(void)
" to original kernel.\n"
" -s, --kexec-file-syscall Use file based syscall for kexec operation\n"
" -d, --debug Enable debugging to help spot a failure.\n"
+ " -S, --status Return 0 if the type (by default crash) is loaded.\n"
"\n"
"Supported kernel file types and options: \n");
for (i = 0; i < file_types; i++) {
@@ -981,7 +1006,7 @@ void usage(void)
printf("\n");
}
-static int kexec_loaded(void)
+static int __kexec_loaded(const char *file)
{
long ret = -1;
FILE *fp;
@@ -992,7 +1017,7 @@ static int kexec_loaded(void)
if (xen_present())
return 1;
- fp = fopen("/sys/kernel/kexec_loaded", "r");
+ fp = fopen(file, "r");
if (fp == NULL)
return -1;
@@ -1015,6 +1040,12 @@ static int kexec_loaded(void)
return (int)ret;
}
+static int kexec_loaded(void)
+{
+ return __kexec_loaded("/sys/kernel/kexec_loaded");
+}
+
+
/*
* Remove parameter from a kernel command line. Helper function by get_command_line().
*/
@@ -1204,6 +1235,7 @@ int main(int argc, char *argv[])
int do_unload = 0;
int do_reuse_initrd = 0;
+ int do_status = 0;
void *entry = 0;
char *type = 0;
char *endptr;
@@ -1345,6 +1377,9 @@ int main(int argc, char *argv[])
/* We already parsed it. Nothing to do. */
break;
+ do_status = 1;
+ break;
break;
}
@@ -1355,6 +1390,20 @@ int main(int argc, char *argv[])
if (skip_sync)
do_sync = 0;
+ if (do_status) {
+ if (kexec_flags == 0)
+ kexec_flags = KEXEC_ON_CRASH;
+ do_load = 0;
+ do_reuse_initrd = 0;
+ do_unload = 0;
+ do_load = 0;
+ do_shutdown = 0;
+ do_sync = 0;
+ do_ifdown = 0;
+ do_exec = 0;
+ do_load_jump_back_helper = 0;
+ }
+
if (do_load && (kexec_flags & KEXEC_ON_CRASH) &&
!is_crashkernel_mem_reserved()) {
die("Memory for crashkernel is not reserved\n"
@@ -1392,7 +1441,9 @@ int main(int argc, char *argv[])
check_reuse_initrd();
arch_reuse_initrd();
}
-
+ if (do_status) {
+ result = k_status(kexec_flags);
+ }
if (do_unload) {
if (do_kexec_file_syscall)
result = kexec_file_unload(kexec_file_flags);
diff --git a/kexec/kexec.h b/kexec/kexec.h
index 9194f1c..2b06f59 100644
--- a/kexec/kexec.h
+++ b/kexec/kexec.h
@@ -219,6 +219,7 @@ extern int file_types;
#define OPT_TYPE 't'
#define OPT_PANIC 'p'
#define OPT_KEXEC_FILE_SYSCALL 's'
+#define OPT_STATUS 'S'
#define OPT_MEM_MIN 256
#define OPT_MEM_MAX 257
#define OPT_REUSE_INITRD 258
@@ -245,8 +246,9 @@ extern int file_types;
{ "reuseinitrd", 0, 0, OPT_REUSE_INITRD }, \
{ "kexec-file-syscall", 0, 0, OPT_KEXEC_FILE_SYSCALL }, \
{ "debug", 0, 0, OPT_DEBUG }, \
+ { "status", 0, 0, OPT_STATUS }, \
-#define KEXEC_OPT_STR "h?vdfxyluet:ps"
+#define KEXEC_OPT_STR "h?vdfxyluet:psS"
extern void dbgprint_mem_range(const char *prefix, struct memory_range *mr, int nr_mr);
extern void die(const char *fmt, ...)
@@ -311,5 +313,6 @@ int xen_present(void);
int xen_kexec_load(struct kexec_info *info);
int xen_kexec_unload(uint64_t kexec_flags);
void xen_kexec_exec(void);
+int xen_kexec_status(uint64_t kexec_flags);
#endif /* KEXEC_H */
--
2.5.5
_______________________________________________
kexec mailing list
http://lists.infradead.org/mailman/listinfo/kexec
Pratyush Anand
2016-11-15 04:48:02 UTC
Permalink
Heya!
as it may be easier to review and provide input then me going back and forth.
Hummmm..its confusing infact. Patch 1/2 does not belong to kexec-tools
repository. patch 2/2 is independent in itself, so send 2/2 individually
to kexec list and once it is getting acked, you can send only 1/2 to
xen-devel list.
Anyhow the patches are to help with the various distro's poking in
/sys/../kexec to figure out whether an kexec image is loaded.
This can be done using the -S parameter now with the patch #2.
Also I add an hypercall to Xen so that if kexec is running under Xen
the same information can be retrieved (see patch #1).
~Pratyush
Daniel Kiper
2016-11-15 09:36:12 UTC
Permalink
Post by Konrad Rzeszutek Wilk
The tools that use kexec are asynchronous in nature and do
not keep state changes. As such provide an hypercall to find
out whether an image has been loaded for either type.
Note: No need to modify XSM as it has one size fits all
check and does not check for subcommands.
---
v0: Internal version.
v1: Dropped Reviewed-by, posting on xen-devel.
---
tools/libxc/include/xenctrl.h | 8 ++++++++
tools/libxc/xc_kexec.c | 27 +++++++++++++++++++++++++++
xen/common/kexec.c | 25 +++++++++++++++++++++++++
xen/include/public/kexec.h | 11 +++++++++++
4 files changed, 71 insertions(+)
diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index 2c83544..aa5d798 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -2574,6 +2574,14 @@ int xc_kexec_load(xc_interface *xch, uint8_t type, uint16_t arch,
*/
int xc_kexec_unload(xc_interface *xch, int type);
+/*
+ * Find out whether the image has been succesfully loaded.
+ *
+ * The can be either KEXEC_TYPE_DEFAULT or KEXEC_TYPE_CRASH.
+ * If zero is returned that means the image is loaded for the type.
+ */
+int xc_kexec_status(xc_interface *xch, int type);
+
typedef xenpf_resource_entry_t xc_resource_entry_t;
/*
diff --git a/tools/libxc/xc_kexec.c b/tools/libxc/xc_kexec.c
index 1cceb5d..95d36ff 100644
--- a/tools/libxc/xc_kexec.c
+++ b/tools/libxc/xc_kexec.c
return ret;
}
+
+int xc_kexec_status(xc_interface *xch, int type)
+{
+ DECLARE_HYPERCALL;
+ DECLARE_HYPERCALL_BUFFER(xen_kexec_status_t, status);
+ int ret = -1;
+
+ status = xc_hypercall_buffer_alloc(xch, status, sizeof(*status));
+ if ( status == NULL )
+ {
+ PERROR("Count not alloc buffer for kexec status hypercall");
Could not? It looks that you copied this from existing code. Could you
send separate patch fixing this issue in two other places too?
Post by Konrad Rzeszutek Wilk
+ goto out;
+ }
+
+ status->type = type;
+
+ hypercall.op = __HYPERVISOR_kexec_op;
+ hypercall.arg[0] = KEXEC_CMD_kexec_status;
+ hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(status);
+
+ ret = do_xen_hypercall(xch, &hypercall);
+
+ xc_hypercall_buffer_free(xch, status);
+
+ return ret;
+}
diff --git a/xen/common/kexec.c b/xen/common/kexec.c
index c83d48f..1148f85 100644
--- a/xen/common/kexec.c
+++ b/xen/common/kexec.c
@@ -1169,6 +1169,28 @@ static int kexec_unload(XEN_GUEST_HANDLE_PARAM(void) uarg)
return kexec_do_unload(&unload);
}
+static int kexec_status(XEN_GUEST_HANDLE_PARAM(void) uarg)
+{
+ xen_kexec_status_t status;
+ int base, bit, pos;
+
+ if ( unlikely(copy_from_guest(&status, uarg, 1)) )
+ return -EFAULT;
+
+ if ( test_bit(KEXEC_FLAG_IN_PROGRESS, &kexec_flags) )
+ return -EBUSY;
+
+ if ( kexec_load_get_bits(status.type, &base, &bit) )
+ return -EINVAL;
+
+ pos = (test_bit(bit, &kexec_flags) != 0);
+
+ if ( !test_bit(base + pos, &kexec_flags) )
+ return -ENOENT;
+
+ return 0;
+}
+
static int do_kexec_op_internal(unsigned long op,
XEN_GUEST_HANDLE_PARAM(void) uarg,
bool_t compat)
@@ -1208,6 +1230,9 @@ static int do_kexec_op_internal(unsigned long op,
ret = kexec_unload(uarg);
break;
+ ret = kexec_status(uarg);
+ break;
}
return ret;
diff --git a/xen/include/public/kexec.h b/xen/include/public/kexec.h
index a6a0a88..29dcb5d 100644
--- a/xen/include/public/kexec.h
+++ b/xen/include/public/kexec.h
@@ -227,6 +227,17 @@ typedef struct xen_kexec_unload {
} xen_kexec_unload_t;
DEFINE_XEN_GUEST_HANDLE(xen_kexec_unload_t);
+/*
+ * Figure out whether we have an image loaded. An return value of
+ * zero indicates success while XEN_ENODEV implies no image loaded.
It seems to me that you thought about -ENOENT instead of XEN_ENODEV.

If you fix both things then Reviewed-by: Daniel Kiper <***@oracle.com>

Daniel
David Vrabel
2016-11-15 10:51:11 UTC
Permalink
Post by Konrad Rzeszutek Wilk
The tools that use kexec are asynchronous in nature and do
not keep state changes. As such provide an hypercall to find
out whether an image has been loaded for either type.
Note: No need to modify XSM as it has one size fits all
check and does not check for subcommands.
[...]
Post by Konrad Rzeszutek Wilk
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -2574,6 +2574,14 @@ int xc_kexec_load(xc_interface *xch, uint8_t type, uint16_t arch,
*/
int xc_kexec_unload(xc_interface *xch, int type);
+/*
+ * Find out whether the image has been succesfully loaded.
+ *
+ * The can be either KEXEC_TYPE_DEFAULT or KEXEC_TYPE_CRASH.
+ * If zero is returned that means the image is loaded for the type.
Suggest return 0 if an image is not loaded, 1 if an image is loaded, but
I'll leave this for the toolstack maintainers to decide.
Post by Konrad Rzeszutek Wilk
--- a/xen/common/kexec.c
+++ b/xen/common/kexec.c
@@ -1169,6 +1169,28 @@ static int kexec_unload(XEN_GUEST_HANDLE_PARAM(void) uarg)
return kexec_do_unload(&unload);
}
+static int kexec_status(XEN_GUEST_HANDLE_PARAM(void) uarg)
+{
+ xen_kexec_status_t status;
+ int base, bit, pos;
+
+ if ( unlikely(copy_from_guest(&status, uarg, 1)) )
+ return -EFAULT;
+
+ if ( test_bit(KEXEC_FLAG_IN_PROGRESS, &kexec_flags) )
+ return -EBUSY;
No need to check in progress here.
Post by Konrad Rzeszutek Wilk
+
+ if ( kexec_load_get_bits(status.type, &base, &bit) )
+ return -EINVAL;
+
+ pos = (test_bit(bit, &kexec_flags) != 0);
+
+ if ( !test_bit(base + pos, &kexec_flags) )
+ return -ENOENT;
return !!test_bit(...);

It also occurs to be that this testing of bits races with
kexec_swap_image(). This race also affects kexec_exec().
Post by Konrad Rzeszutek Wilk
static int do_kexec_op_internal(unsigned long op,
XEN_GUEST_HANDLE_PARAM(void) uarg,
bool_t compat)
@@ -1208,6 +1230,9 @@ static int do_kexec_op_internal(unsigned long op,
ret = kexec_unload(uarg);
break;
+ ret = kexec_status(uarg);
+ break;
Tabs!
Post by Konrad Rzeszutek Wilk
--- a/xen/include/public/kexec.h
+++ b/xen/include/public/kexec.h
@@ -227,6 +227,17 @@ typedef struct xen_kexec_unload {
} xen_kexec_unload_t;
DEFINE_XEN_GUEST_HANDLE(xen_kexec_unload_t);
+/*
+ * Figure out whether we have an image loaded. An return value of
+ * zero indicates success while XEN_ENODEV implies no image loaded.
+ *
+ * Type must be one of KEXEC_TYPE_DEFAULT or KEXEC_TYPE_CRASH.
Return 0 if no image is loaded. 1 if an image is loaded and -ve on an error.

David
Loading...