#define RUN_CMD "run"
#define RUN_SCRIPT "/etc/rs.single" /* Default script for 'run' */
+#define SELF_BINARY "self"
+#define SELF_REQ_PATH "/dev/null"
#define PATH_CONFIG _PATH_SYSTEM_CONF /* Default config file */
#define DEFAULT_LU_STATE SEF_LU_STATE_WORK_FREE /* Default lu state */
#define DEFAULT_LU_MAXTIME 0 /* Default lu max time */
#define OPT_COPY "-c" /* copy executable image */
#define OPT_REUSE "-r" /* reuse executable image */
#define OPT_NOBLOCK "-n" /* unblock caller immediately */
+#define OPT_REPLICA "-p" /* create replica for the service */
/* Define names for arguments provided to this utility. The first few
* arguments are required and have a known index. Thereafter, some optional
PRIVATE int do_run= 0; /* 'run' command instead of 'up' */
PRIVATE char *req_label = NULL;
PRIVATE char *req_path = NULL;
+PRIVATE char *req_path_self = SELF_REQ_PATH;
PRIVATE char *req_args = "";
PRIVATE int req_major = 0;
PRIVATE int req_dev_style = STYLE_NDEV;
fprintf(stderr, "Warning, %s\n", problem);
fprintf(stderr, "Usage:\n");
fprintf(stderr,
- " %s [%s %s %s] (up|run|update) <binary> [%s <args>] [%s <special>] [%s <style>] [%s <ticks>] [%s <path>] [%s <name>] [%s <path>] [%s <state>] [%s <time>]\n",
- app_name, OPT_COPY, OPT_REUSE, OPT_NOBLOCK,
+ " %s [%s %s %s %s] (up|run|update) <binary|%s> [%s <args>] [%s <special>] [%s <style>] [%s <ticks>] [%s <path>] [%s <name>] [%s <path>] [%s <state>] [%s <time>]\n",
+ app_name, OPT_COPY, OPT_REUSE, OPT_NOBLOCK, OPT_REPLICA, SELF_BINARY,
ARG_ARGS, ARG_DEV, ARG_DEVSTYLE, ARG_PERIOD, ARG_SCRIPT,
ARG_LABELNAME, ARG_CONFIG, ARG_LU_STATE, ARG_LU_MAXTIME);
fprintf(stderr, " %s down label\n", app_name);
if(p_flag)
rs_start.rss_flags |= RSS_REPLICA;
+ req_path = argv[optind+ARG_PATH];
+ if(req_nr == RS_UPDATE && !strcmp(req_path, SELF_BINARY)) {
+ req_config = NULL;
+ req_path = req_path_self;
+ rs_start.rss_flags |= RSS_SELF_LU;
+ }
+
if (do_run)
{
/* Set default recovery script for RUN */
}
/* Verify the name of the binary of the system service. */
- req_path = argv[optind+ARG_PATH];
- if (req_path[0] != '/') {
- print_usage(argv[ARG_NAME], "binary should be absolute path");
- exit(EINVAL);
- }
-
- if (stat(req_path, &stat_buf) == -1) {
- perror(req_path);
- fprintf(stderr, "couldn't get stat binary\n");
- exit(errno);
- }
- if (! (stat_buf.st_mode & S_IFREG)) {
- print_usage(argv[ARG_NAME], "binary is not a regular file");
- exit(EINVAL);
+ if(!(rs_start.rss_flags & RSS_SELF_LU)) {
+ if (req_path[0] != '/') {
+ print_usage(argv[ARG_NAME], "binary should be absolute path");
+ exit(EINVAL);
+ }
+ if (stat(req_path, &stat_buf) == -1) {
+ perror(req_path);
+ fprintf(stderr, "couldn't get stat binary\n");
+ exit(errno);
+ }
+ if (! (stat_buf.st_mode & S_IFREG)) {
+ print_usage(argv[ARG_NAME], "binary is not a regular file");
+ exit(EINVAL);
+ }
}
/* Get HZ. */
/* no extra arguments required */
}
+ if((rs_start.rss_flags & RSS_SELF_LU) && !req_label) {
+ print_usage(argv[ARG_NAME], "label option mandatory for target action");
+ exit(EINVAL);
+ }
+
/* Return the request number if no error were found. */
return(req_nr);
}
#define RSS_REUSE 0x04 /* Try to reuse previously copied binary */
#define RSS_NOBLOCK 0x08 /* unblock caller immediately */
#define RSS_REPLICA 0x10 /* keep a replica of the service */
+#define RSS_SELF_LU 0x20 /* perform self update */
/* Common definitions. */
#define RS_NR_CONTROL 8
* service has a period, a status request will be forced in the next period.
*/
struct rproc *old_rp, *new_rp, *exiting_rp, *surviving_rp;
+ struct rproc **rps;
+ int nr_rps, i;
old_rp = rupdate.rp;
new_rp = old_rp->r_new_rp;
/* Send a late reply if necessary. */
late_reply(old_rp, result);
- /* Unpublish and cleanup the version that has to die out and mark the other
+ /* Cleanup the version that has to die out and mark the other
* version as no longer updating.
*/
surviving_rp->r_flags &= ~RS_UPDATING;
- cleanup_service(exiting_rp);
+ get_service_instances(exiting_rp, &rps, &nr_rps);
+ for(i=0;i<nr_rps;i++) {
+ cleanup_service(rps[i]);
+ }
if(rs_verbose)
- printf("RS: service %s ended the update\n", srv_to_string(surviving_rp));
+ printf("RS: %s ended the update\n", srv_to_string(surviving_rp));
}
/*===========================================================================*
struct rproc *new_rp;
struct rprocpub *rpub;
struct rs_start rs_start;
- int noblock;
+ int noblock, do_self_update;
int s;
char label[RS_MAX_LABEL_LEN];
int lu_state;
return s;
}
noblock = (rs_start.rss_flags & RSS_NOBLOCK);
+ do_self_update = (rs_start.rss_flags & RSS_SELF_LU);
s = check_request(&rs_start);
if (s != OK) {
return s;
return EBUSY;
}
- /* Allocate a system service slot for the new version. */
- s = alloc_slot(&new_rp);
- if(s != OK) {
- printf("RS: do_update: unable to allocate a new slot: %d\n", s);
- return s;
- }
+ /* A self update live updates a service instance into a replica, a regular
+ * update live updates a service instance into a new version, as specified
+ * by the given binary.
+ */
+ if(do_self_update) {
+ struct rproc *r_next_rp;
+ if(rs_verbose)
+ printf("RS: %s performs self update\n", srv_to_string(rp));
- /* Initialize the slot as requested. */
- s = init_slot(new_rp, &rs_start, m_ptr->m_source);
- if(s != OK) {
- printf("RS: do_update: unable to init the new slot: %d\n", s);
- return s;
+ /* Save information about existing replica (if any). */
+ r_next_rp = rp->r_next_rp;
+ rp->r_next_rp = NULL;
+
+ /* Clone the system service and use the replica as the new version. */
+ s = clone_service(rp);
+ if(s != OK) {
+ printf("RS: do_update: unable to clone service: %d\n", s);
+ return s;
+ }
+ new_rp = rp->r_next_rp;
+ new_rp->r_prev_rp = NULL;
+
+ /* Restore information about existing replica (if any). */
+ rp->r_next_rp = r_next_rp;
}
+ else {
+ if(rs_verbose)
+ printf("RS: %s performs regular update\n", srv_to_string(rp));
- /* Let the new version inherit defaults from the old one. */
- inherit_service_defaults(rp, new_rp);
+ /* Allocate a system service slot for the new version. */
+ s = alloc_slot(&new_rp);
+ if(s != OK) {
+ printf("RS: do_update: unable to allocate a new slot: %d\n", s);
+ return s;
+ }
- /* Create new version of the service but don't let it run. */
- s = create_service(new_rp);
- if(s != OK) {
- printf("RS: do_update: unable to create a new service: %d\n", s);
- return s;
+ /* Initialize the slot as requested. */
+ s = init_slot(new_rp, &rs_start, m_ptr->m_source);
+ if(s != OK) {
+ printf("RS: do_update: unable to init the new slot: %d\n", s);
+ return s;
+ }
+
+ /* Let the new version inherit defaults from the old one. */
+ inherit_service_defaults(rp, new_rp);
+
+ /* Create new version of the service but don't let it run. */
+ s = create_service(new_rp);
+ if(s != OK) {
+ printf("RS: do_update: unable to create a new service: %d\n", s);
+ return s;
+ }
}
/* Link old version to new version and mark both as updating. */