/** * cr_hand_abort - wrapper/helper for CR_OP_HAND_ABORT * @file: (struct file *) of the control node * @flags: abort type * * DESCRIPTION: * This function dispatches to the checkpoint-time or restart-time * "abort" code. */ int cr_hand_abort(struct file *filp, unsigned int flags) { cr_task_t *cr_task; int retval; CR_KTRACE_FUNC_ENTRY(); // Lookup this task retval = -ESRCH; cr_task = cr_task_get(current); if (!cr_task) { // No matching task found. CR_ERR("%s: No matching task found!", __FUNCTION__); goto out_no_task; } // Dispatch according to the matching request if (cr_task->chkpt_proc_req) { retval = cr_chkpt_abort(cr_task, flags); } else if (cr_task->rstrt_proc_req) { retval = cr_rstrt_abort(cr_task, flags); } else { // No matching request found. CR_ERR("%s: No matching request found!", __FUNCTION__); } cr_task_put(cr_task); out_no_task: CR_KTRACE_FUNC_EXIT("Returning %d", retval); return retval; }
/** * cr_proc_cleanup - Initialization code * * DESCRIPTION: * This function removes /proc/checkpoint and /proc/checkpoint/ctrl */ void cr_proc_cleanup(void) { CR_KTRACE_FUNC_ENTRY(); remove_proc_entry("ctrl", proc_checkpoint); remove_proc_entry("checkpoint", cr_proc_root); }
static int ctrl_open(struct inode * inode, struct file * file) { cr_pdata_t *priv; CR_KTRACE_FUNC_ENTRY(); CR_NO_LOCKS(); priv = cr_kmem_cache_zalloc(cr_pdata_t, cr_pdata_cachep, GFP_KERNEL); if (priv) { file->private_data = (void*)priv; } return priv ? 0 : -ENOMEM; }
static unsigned int ctrl_poll(struct file *filp, poll_table *wait) { unsigned int mask; cr_pdata_t *priv; CR_KTRACE_FUNC_ENTRY(); priv = filp->private_data; if (priv && priv->rstrt_req) { mask = cr_rstrt_poll(filp, wait); } else if (priv && priv->chkpt_req) { mask = cr_chkpt_poll(filp, wait); } else { mask = POLLERR; } return mask; }
static int ctrl_release(struct inode * inode, struct file * file) { cr_pdata_t *priv; CR_KTRACE_FUNC_ENTRY(); priv = file->private_data; if (priv) { cr_chkpt_req_release(file, priv); cr_rstrt_req_release(file, priv); cr_phase1_release(file, priv); cr_phase2_release(file, priv); kmem_cache_free(cr_pdata_cachep, priv); file->private_data = NULL; } return 0; }
/** * cr_proc_init - Initialization code * * DESCRIPTION: * This function registers /proc/checkpoint and /proc/checkpoint/ctrl */ int __init cr_proc_init(void) { CR_KTRACE_FUNC_ENTRY(); proc_checkpoint = create_proc_entry("checkpoint", S_IFDIR, cr_proc_root); if (proc_checkpoint == NULL) { CR_ERR("proc_create_entry(/proc/checkpoint/) failed"); return -ENOMEM; } proc_ctrl = create_proc_entry("ctrl", S_IFREG | S_IRUGO | S_IWUGO, proc_checkpoint); if (proc_ctrl == NULL) { CR_ERR("proc_create_entry(/proc/checkpoint/ctrl) failed"); return -ENOMEM; } proc_ctrl->proc_fops = &cr_ctrl_fops; return 0; }
/** * cr_hand_complete - wrapper/helper for CR_OP_HAND_DONE * @file: (struct file *) of the control node * * DESCRIPTION: * This function dispatches to the checkpoint-time or restart-time * post-handler "task_complete" code. */ int cr_hand_complete(struct file *filp, unsigned int flags) { cr_task_t *cr_task; int retval; CR_KTRACE_FUNC_ENTRY(); retval = -EINVAL; if (flags & ~CR_HOLD_BOTH) { CR_ERR("%s: invalid flags", __FUNCTION__); goto out_no_task; } // Lookup this task retval = -ESRCH; cr_task = cr_task_get(current); if (!cr_task) { // No matching task found. CR_ERR("%s: No matching task found!", __FUNCTION__); goto out_no_task; } // Dispatch according to the matching request if (cr_task->chkpt_proc_req) { retval = cr_chkpt_task_complete(cr_task, flags & CR_HOLD_CONT); } else if (cr_task->rstrt_proc_req) { retval = cr_rstrt_task_complete(cr_task, flags & CR_HOLD_RSTRT, /* need_lock= */ 1); } else { // No matching request found. CR_ERR("%s: No matching request found!", __FUNCTION__); } cr_task_put(cr_task); out_no_task: CR_KTRACE_FUNC_EXIT("Returning %d", retval); return retval; }
const char * cr_location2path(cr_location_t *loc, char *buf, int size) { CR_PATH_DECL(path); char *name = NULL; CR_KTRACE_FUNC_ENTRY(); if (loc->filp) { /* It's a file */ CR_PATH_GET_FILE(path, loc->filp); name = cr_getpath(path, buf, size); path_put(path); } else if (loc->fs) { /* It's a directory */ CR_PATH_GET_FS(path, loc->fs->pwd); name = cr_getpath(path, buf, size - 2); path_put(path); if (name) { int len = strlen(buf); buf[len+0] = '/'; buf[len+1] = '.'; buf[len+2] = '\0'; } } else { /* I don't know what it is */ name = ""; } if (!name) { name = ERR_PTR(-EBADF); } return name; }
/** * ctrl_ioctl - ioctl() method for the C/R control node * @inode: (struct inode *) of the control node * @file: (struct file *) of the control node * @op: The operation/command to perform * @arg: The (optional) argument to the command as an unsigned long * * DESCRIPTION: * This function is the ioctl() method in the file_operations for * the C/R control node. It acts as a dispatcher to the functions * which do the real work. */ static int ctrl_ioctl(struct inode *inode, struct file *file, unsigned int op, unsigned long arg) { CR_KTRACE_FUNC_ENTRY("op=%08x arg=0x%lx", op, arg); switch(op) { // // Calls from libcr: // // XXX: When adding cases here, also add to the ioctl32 init/cleanup // code below and to the big switch in cr_compat.c. case CR_OP_HAND_CHKPT: return cr_dump_self(file, arg); case CR_OP_HAND_ABORT: return cr_hand_abort(file, arg); case CR_OP_HAND_SUSP: return cr_suspend(file, (struct timeval __user *)arg); case CR_OP_HAND_PHASE1: return cr_phase1_register(file, (int)arg); case CR_OP_HAND_PHASE2: return cr_phase2_register(file, (int)arg); case CR_OP_HAND_SRC: return cr_rstrt_src(file, (char __user *)arg); case CR_OP_HAND_CHKPT_INFO: return cr_chkpt_info(file, (struct cr_chkpt_info __user *)arg); case CR_OP_HAND_DONE: return cr_hand_complete(file, arg); // // Calls from cr_checkpoint: // case CR_OP_CHKPT_REQ: return cr_chkpt_req(file, (struct cr_chkpt_args __user *)arg); case CR_OP_CHKPT_REAP: return cr_chkpt_reap(file); case CR_OP_CHKPT_FWD: return cr_chkpt_fwd(file, (struct cr_fwd_args __user *)arg); case CR_OP_CHKPT_LOG: return cr_chkpt_log(file, (struct cr_log_args __user *)arg); // // Calls from cr_restart: // case CR_OP_RSTRT_REQ: return cr_rstrt_request_restart(file, (struct cr_rstrt_args __user *)arg); case CR_OP_RSTRT_REAP: return cr_rstrt_reap(file); case CR_OP_RSTRT_CHILD: return cr_rstrt_child(file); case CR_OP_RSTRT_PROCS: return cr_rstrt_procs(file, (struct cr_procs_tbl __user *)arg); case CR_OP_RSTRT_LOG: return cr_rstrt_log(file, (struct cr_log_args __user *)arg); // // General calls // case CR_OP_VERSION: { // Simple enough to do here // User-space must have equal MAJOR and MINOR <= kernel // If we supported multiple major versions then this is // where we could do the "personallity switching". unsigned long major = (arg >> 16); unsigned long minor = (arg & 0xffff); // If major==0, must match minor; otherwise user-MINOR <= kernel-MINOR int match = (major == CR_MODULE_MAJOR) && (major ? (minor <= CR_MODULE_MINOR) : (minor == CR_MODULE_MINOR)); if (!match) { CR_WARN("request from pid %d for unsupported version %d.%d", (int)current->pid, (int)major, (int)minor); } return match ? 0 : -CR_EVERSION; } default: CR_KTRACE_BADPARM("unknown op %x", _IOC_NR(op)); return -ENOTTY; } }