Пример #1
0
/**
 * @brief
 * 		queuestart_action - when queue is stopped or started,
 *		for all jobs in queue and determine their accrue type
 * 		action function for QA_ATR_started.
 *
 * @param[in]	pattr	- pointer to special attributes of an Array Job
 * @param[in]	pobject	- queue which is stopped or started
 * @param[in]	actmode	- not used.
 *
 * @return	int
 * @retval	0	- success
 */
int
queuestart_action(attribute *pattr, void *pobject, int actmode)
{
	job 	*pj;		/* pointer to job */
	long	oldtype;
	long 	newaccruetype = -1;	/* if determining accrue type */
	pbs_queue *pque = (pbs_queue *) pobject;

	if ((pque != NULL) && (server.sv_attr[SRV_ATR_EligibleTimeEnable].at_val.at_long == 1)) {

		if (pattr->at_val.at_long == 0) { /* started = OFF */
			/* queue stopped, start accruing eligible time */
			/* running jobs and jobs accruing ineligible time are exempted */
			/* jobs accruing eligible time are also exempted */

			pj = (job*)GET_NEXT(pque->qu_jobs);

			while (pj != (job*)0) {

				oldtype = pj->ji_wattr[(int)JOB_ATR_accrue_type].at_val.at_long;

				if (oldtype != JOB_RUNNING && oldtype != JOB_INELIGIBLE &&
					oldtype != JOB_ELIGIBLE) {

					/* determination of accruetype not required here */
					(void)update_eligible_time(JOB_ELIGIBLE, pj);
				}

				pj = (job*)GET_NEXT(pj->ji_jobque);
			}

		} else { 			/* started = ON */
			/* determine accrue type and accrue time */

			pj = (job*)GET_NEXT(pque->qu_jobs);

			while (pj != (job*)0) {

				oldtype = pj->ji_wattr[(int)JOB_ATR_accrue_type].at_val.at_long;

				if (oldtype != JOB_RUNNING && oldtype != JOB_INELIGIBLE &&
					oldtype != JOB_ELIGIBLE) {

					newaccruetype = determine_accruetype(pj);
					(void)update_eligible_time(newaccruetype, pj);
				}

				pj = (job*)GET_NEXT(pj->ji_jobque);
			}

			/* if scheduling = True, notify scheduler to start */
			if (server.sv_attr[SRV_ATR_scheduling].at_val.at_long)
				set_scheduler_flag(SCH_SCHEDULE_STARTQ);
		}
	}

	return 0;
}
Пример #2
0
/**
 * @brief
 * 		modify_job_attr - modify the attributes of a job automatically
 *		Used by req_modifyjob() to alter the job attributes and by
 *		stat_update() [see req_stat.c] to update with latest from MOM
 *
 * @param[in,out]	pjob	-	job structure
 * @param[in,out]	plist	-	Pointer to list of attributes
 * @param[in]	perm	-	Permissions of the caller requesting the operation
 * @param[out]	bad	-	Pointer to the attribute index in case of a failed
 */
int
modify_job_attr(job *pjob, svrattrl *plist, int perm, int *bad)
{
	int	   changed_resc;
	int	   allow_unkn;
	long	   i;
	int	   modified = 0;
	attribute *newattr;
	attribute *pre_copy;
	attribute *attr_save;
	attribute *pattr;
	resource  *prc;
	int	   rc;
	int	   newstate = -1;
	int	   newsubstate = -1;
	long	   newaccruetype = -1;

	if (pjob->ji_qhdr->qu_qs.qu_type == QTYPE_Execution)
		allow_unkn = -1;
	else
		allow_unkn = (int)JOB_ATR_UNKN;

	pattr = pjob->ji_wattr;

	/* call attr_atomic_set to decode and set a copy of the attributes.
	 * We need 2 copies: 1 for copying to pattr and 1 for calling the action functions
	 * We can't use the same copy for the action functions because copying to pattr
	 * is a shallow copy and array pointers will be cleared during the copy.
	 */

	newattr = calloc(JOB_ATR_LAST, sizeof(attribute));
	if (newattr == NULL)
		return PBSE_SYSTEM;
	rc = attr_atomic_set(plist, pattr, newattr, job_attr_def, JOB_ATR_LAST,
		allow_unkn, perm, bad);
	if (rc) {
		attr_atomic_kill(newattr, job_attr_def, JOB_ATR_LAST);
		return rc;
	}

	pre_copy = calloc(JOB_ATR_LAST, sizeof(attribute));
	if(pre_copy == NULL) {
		attr_atomic_kill(newattr, job_attr_def, JOB_ATR_LAST);
		return PBSE_SYSTEM;
	}
	attr_atomic_copy(pre_copy, newattr, job_attr_def, JOB_ATR_LAST);

	attr_save = calloc(JOB_ATR_LAST, sizeof(attribute));
	if (attr_save == NULL) {
		attr_atomic_kill(newattr, job_attr_def, JOB_ATR_LAST);
		attr_atomic_kill(pre_copy, job_attr_def, JOB_ATR_LAST);
		return PBSE_SYSTEM;
	}

	attr_atomic_copy(attr_save, pattr, job_attr_def, JOB_ATR_LAST);

	/* If resource limits are being changed ... */

	changed_resc = newattr[(int)JOB_ATR_resource].at_flags & ATR_VFLAG_SET;
	if ((rc == 0) && (changed_resc != 0)) {

		/* first, remove ATR_VFLAG_DEFLT from any value which was set */
		/* it can no longer be a "default" as it explicitly changed   */

		prc = (resource *)GET_NEXT(newattr[(int)JOB_ATR_resource].at_val.at_list);
		while (prc) {
			if ((prc->rs_value.at_flags & (ATR_VFLAG_MODIFY|ATR_VFLAG_DEFLT)) == (ATR_VFLAG_MODIFY|ATR_VFLAG_DEFLT))
				prc->rs_value.at_flags &= ~ATR_VFLAG_DEFLT;

			if ((prc->rs_value.at_flags & (ATR_VFLAG_MODIFY|ATR_VFLAG_SET)) == (ATR_VFLAG_MODIFY|ATR_VFLAG_SET)) {
				/* if being changed at all, see if "select" */
				if (prc->rs_defin == pseldef) {
					/* select is modified, recalc chunk sums */
					rc = set_chunk_sum(&prc->rs_value,
						&newattr[(int)JOB_ATR_resource]);
					if (rc)
						break;
				}
			}
			prc = (resource *)GET_NEXT(prc->rs_link);
		}

		/* Manager/Operator can modify job just about any old way     */
		/* So, the following checks are made only if not the Op/Admin */

		if ((perm & (ATR_DFLAG_MGWR | ATR_DFLAG_OPWR)) == 0) {
			if (pjob->ji_qs.ji_state == JOB_STATE_RUNNING) {

				/* regular user cannot raise the limits of a running job */

				if ((comp_resc(&pjob->ji_wattr[(int)JOB_ATR_resource],
					&newattr[(int)JOB_ATR_resource]) == -1) ||
					comp_resc_lt)
					rc = PBSE_PERM;

			}

			/* Also check against queue, system and entity limits */


			if (rc == 0) {
				rc =  chk_resc_limits(&newattr[(int)JOB_ATR_resource],
					pjob->ji_qhdr);
			}
			if (rc == 0) {
				rc = check_entity_resc_limit_max(pjob, pjob->ji_qhdr,
					&newattr[(int)JOB_ATR_resource]);
				if (rc == 0) {
					rc = check_entity_resc_limit_queued(pjob, pjob->ji_qhdr,
						&newattr[(int)JOB_ATR_resource]);
					if (rc == 0)
					{
						rc = check_entity_resc_limit_max(pjob, NULL,
							&newattr[(int)JOB_ATR_resource]);
						if (rc == 0)
							rc = check_entity_resc_limit_queued(pjob, NULL,
								&newattr[(int)JOB_ATR_resource]);
					}
				}
			}
		}
	}

	/* special check on permissions for hold */

	if ((rc == 0) &&
		(newattr[(int)JOB_ATR_hold].at_flags & ATR_VFLAG_MODIFY)) {
		svrattrl *hold_e = find_name_in_svrattrl(plist, ATTR_h);
		/* don't perform permission check if Hold_Types attribute */
		/* was set in a hook script (special privilege) */
		if ((hold_e == NULL) ||
			((hold_e->al_flags & ATR_VFLAG_HOOK) == 0)) {
			i = newattr[(int)JOB_ATR_hold].at_val.at_long ^
				(pattr+(int)JOB_ATR_hold)->at_val.at_long;
			rc = chk_hold_priv(i, perm);
		}
	}


	if ((rc == 0) &&
		((newattr[(int)JOB_ATR_userlst].at_flags & ATR_VFLAG_MODIFY) ||
			(newattr[(int)JOB_ATR_grouplst].at_flags & ATR_VFLAG_MODIFY))) {
		/* Need to reset execution uid and gid */
		rc = set_objexid((void *)pjob, JOB_OBJECT, newattr);
	}

	if (rc) {
		attr_atomic_kill(newattr, job_attr_def, JOB_ATR_LAST);
		attr_atomic_kill(attr_save, job_attr_def, JOB_ATR_LAST);
		attr_atomic_kill(pre_copy, job_attr_def, JOB_ATR_LAST);
		return (rc);
	}

	/* OK, if resources changed, reset entity sums */

	if (changed_resc) {
		account_entity_limit_usages(pjob, NULL,
				&newattr[(int)JOB_ATR_resource], INCR, ETLIM_ACC_ALL_RES);
		account_entity_limit_usages(pjob, pjob->ji_qhdr,
				&newattr[(int)JOB_ATR_resource], INCR, ETLIM_ACC_ALL_RES);
	}

	/* Now copy the new values into the job attribute array for the purposes of running the action functions */

	for (i = 0; i < JOB_ATR_LAST; i++) {
		if (newattr[i].at_flags & ATR_VFLAG_MODIFY) {
			/*
			 * The function update_eligible_time() expects it is the only one setting accrue_type.
			 * If we set it here, it will get confused.  There is no action function for accrue_type,
			 * so pre-setting it for the action function calls isn't required.
			 */
			if (i == JOB_ATR_accrue_type)
				continue;
			job_attr_def[i].at_free(&pattr[i]);
			if ((pre_copy[i].at_type == ATR_TYPE_LIST) ||
				(pre_copy[i].at_type == ATR_TYPE_RESC)) {
				list_move(&pre_copy[i].at_val.at_list,
					  &pattr[i].at_val.at_list);
			} else {
				pattr[i] = pre_copy[i];
			}
			/* ATR_VFLAG_MODCACHE will be included if set */
			pattr[i].at_flags = pre_copy[i].at_flags;
		}
	}

	for (i = 0; i < JOB_ATR_LAST; i++) {
		/* Check newattr instead of pattr for modify.  It is possible that
		 * the attribute already has the modify flag before we added the new attributes to it.
		 * We only want to call the action functions for attributes which are being modified by this function.
		 */
		if (newattr[i].at_flags & ATR_VFLAG_MODIFY) {
			if ((job_attr_def[i].at_flags & ATR_DFLAG_NOSAVM) == 0)
				modified = 1;	/* full save to disk for job */
			if (job_attr_def[i].at_action) {
				rc = job_attr_def[i].at_action(&newattr[i],
					pjob, ATR_ACTION_ALTER);
				if (rc) {
					*bad = i;
					break;
				}
			}
		}
	}
	if (rc) {
		attr_atomic_copy(pjob->ji_wattr, attr_save, job_attr_def, JOB_ATR_LAST);
		free(pre_copy);
		attr_atomic_kill(newattr, job_attr_def, JOB_ATR_LAST);
		attr_atomic_kill(attr_save, job_attr_def, JOB_ATR_LAST);
		return (rc);
	}

	/* The action functions may have modified the attributes, need to set them to newattr2 */
	for (i = 0; i < JOB_ATR_LAST; i++) {
		if (newattr[i].at_flags & ATR_VFLAG_MODIFY) {
			job_attr_def[i].at_free(&pattr[i]);
			switch (i) {
				case JOB_ATR_state:
					newstate = state_char2int(newattr[i].at_val.at_char);
					break;
				case JOB_ATR_substate:
					newsubstate = newattr[i].at_val.at_long;
					break;
				case JOB_ATR_accrue_type:
					newaccruetype = newattr[i].at_val.at_long;
					break;
				default:
					if ((newattr[i].at_type == ATR_TYPE_LIST) ||
						(newattr[i].at_type == ATR_TYPE_RESC)) {
						list_move(&newattr[i].at_val.at_list,
							  &pattr[i].at_val.at_list);
					} else {
						pattr[i] = newattr[i];
					}
			}
			/* ATR_VFLAG_MODCACHE will be included if set */
			pattr[i].at_flags = newattr[i].at_flags;
		}
	}

	if (newstate != -1 && newsubstate != -1) {
		svr_setjobstate(pjob, newstate, newsubstate);
	}

	if (newaccruetype != -1)
		update_eligible_time(newaccruetype, pjob);

	if (modified)
		pjob->ji_modified = 1;	/* an attr was modified, do full save */

	free(newattr);
	free(pre_copy);
	attr_atomic_kill(attr_save, job_attr_def, JOB_ATR_LAST);
	return (0);
}
Пример #3
0
/**
 * @brief
 * 		Move a job to another queue in this Server.
 *
 * @par
 * 		Check the destination to see if it can accept the job.
 * 		If the job can enter the new queue, dequeue from the existing queue and
 * 		enqueue into the new queue
 *
 * @par
 * 		Note - the destination is specified by the queue's name in the
 *		ji_qs.ji_destin element of the job structure.
 *
 * param[in]	jobp	-	pointer to job to move
 * param[in]	req	-	client request from a qmove client, null if a route
 *
 * @return	int
 * @retval  0	: success
 * @retval -1	: permanent failure or rejection, see pbs_errno
 * @retval  1	: failed but try again later
 */
int
local_move(job *jobp, struct batch_request *req)
{
	pbs_queue *qp;
	char	  *destination = jobp->ji_qs.ji_destin;
	int	   mtype;
	attribute *pattr;
	long	newtype = -1;


	/* search for destination queue */
	if ((qp = find_queuebyname(destination)) == NULL) {
		sprintf(log_buffer,
			"queue %s does not exist",
			destination);
		log_err(-1, __func__, log_buffer);
		pbs_errno = PBSE_UNKQUE;
		return -1;
	}

	/*
	 * if being moved at specific request of administrator, then
	 * checks on queue availability, etc. are skipped;
	 * otherwise all checks are enforced.
	 */

	if (req == NULL) {
		mtype = MOVE_TYPE_Route;	/* route */
	} else if (req->rq_perm & (ATR_DFLAG_MGRD | ATR_DFLAG_MGWR)) {
		mtype =	MOVE_TYPE_MgrMv;	/* privileged move */
	} else {
		mtype = MOVE_TYPE_Move;		/* non-privileged move */
	}

	pbs_errno = svr_chkque(jobp, qp,
		get_hostPart(jobp->ji_wattr[(int)JOB_ATR_job_owner].at_val.at_str),
		mtype);

	if (pbs_errno) {
		/* should this queue be retried? */
		return (should_retry_route(pbs_errno));
	}

	/* dequeue job from present queue, update destination and	*/
	/* queue_rank for new queue and enqueue into destination	*/

	svr_dequejob(jobp);
	jobp->ji_myResv = NULL;
	strncpy(jobp->ji_qs.ji_queue, qp->qu_qs.qu_name, PBS_MAXQUEUENAME);
	jobp->ji_qs.ji_queue[PBS_MAXQUEUENAME] = '\0';

	jobp->ji_wattr[(int)JOB_ATR_qrank].at_val.at_long = ++queue_rank;
	jobp->ji_wattr[(int)JOB_ATR_qrank].at_flags |= ATR_VFLAG_MODCACHE;

	pattr = &jobp->ji_wattr[(int)JOB_ATR_reserve_ID];
	if (qp->qu_resvp) {

		job_attr_def[(int)JOB_ATR_reserve_ID].at_decode(pattr,
			(char *)0, (char *)0, qp->qu_resvp->ri_qs.ri_resvID);
		jobp->ji_myResv = qp->qu_resvp;
	} else {

		job_attr_def[(int)JOB_ATR_reserve_ID].at_decode(pattr,
			(char *)0, (char *)0, (char*)0);
	}

	if (server.sv_attr[(int)SRV_ATR_EligibleTimeEnable].at_val.at_long == 1) {

		newtype = determine_accruetype(jobp);
		if (newtype == -1)
			/* unable to determine accruetype, set it to NEW */
			(void)update_eligible_time(JOB_INITIAL, jobp);
		else
			/* found suiting accruetype, update to this */
			(void)update_eligible_time(newtype, jobp);

	}


	if ((pbs_errno = svr_enquejob(jobp)) != 0)
		return -1;		/* should never ever get here */

	jobp->ji_lastdest = 0;	/* reset in case of another route */

	(void)job_save(jobp, SAVEJOB_FULL);

	/* If a scheduling cycle is in progress, then this moved job may have
	 * had changes resulting from the move that would impact scheduling or
	 * placement, add job to list of jobs which cannot be run in this cycle.
	 */
	if ((req == NULL || (req->rq_conn != scheduler_sock)) && (scheduler_jobs_stat))
		am_jobs_add(jobp);

	return 0;
}