예제 #1
0
//------------------------------------------------------------------------------
//
//  Function:  UpdatePeriod
//
VOID
UpdatePeriod(
    UINT32 periodMSec
    )
{
    UINT32 period, match;
    INT32 delta;
    UINT64 offsetMSec = periodMSec;
    UINT64 tickCount = OALGetTickCount();
    INT nDelay;

    // Calculate count difference
    period = (UINT32)MSEC_TO_TICK(offsetMSec);

    nDelay = min(period, DELTA_TIME);
    // This is compare value
    match = ((UINT32)MSEC_TO_TICK(tickCount)) + nDelay;

    delta = (INT32)(OALTimerGetCount()+ g_oalTimerContext.margin - match);

    // If we are behind, issue interrupt as soon as possible
    if (delta > 0)
    {
        match += MSEC_TO_TICK(1);
    }

    // Save off match value
    g_oalTimerContext.match = match;

    // Set timer match value
    OALTimerSetCompare(match);
}
예제 #2
0
/*FUNCTION**********************************************************************
 *
 * Function Name : OSA_SemaphoreWait
 * Description   : This function checks the semaphore's counting value, if it is
 * positive, decreases it and returns osaStatus_Success, otherwise, timeout
 * will be used for wait. The parameter timeout indicates how long should wait
 * in milliseconds. Pass osaWaitForever_c to wait indefinitely, pass 0 will
 * return osaStatus_Timeout immediately if semaphore is not positive.
 * This function returns osaStatus_Success if the semaphore is received, returns
 * osaStatus_Timeout if the semaphore is not received within the specified
 * 'timeout', returns osaStatus_Error if any errors occur during waiting.
 *
 *END**************************************************************************/
osaStatus_t OSA_SemaphoreWait(osaSemaphoreId_t semId, uint32_t millisec)
{
#if osNumberOfSemaphores
  uint32_t timeoutTicks;
  if(semId == NULL)
  {
    return osaStatus_Error;
  }
  semaphore_t sem = (semaphore_t)semId;
  
  /* Convert timeout from millisecond to tick. */
  if (millisec == osaWaitForever_c)
  {
    timeoutTicks = portMAX_DELAY;
  }
  else
  {
    timeoutTicks = MSEC_TO_TICK(millisec);
  }
  
  if (xSemaphoreTake(sem, timeoutTicks)==pdFALSE)
  {
    return osaStatus_Timeout; /* timeout */
  }
  else
  {
    return osaStatus_Success; /* semaphore taken */
  }
#else
  (void)semId; 
  (void)millisec;
  return osaStatus_Error;
#endif  
}
/*FUNCTION**********************************************************************
 *
 * Function Name : OSA_MutexLock
 * Description   : This function checks the mutex's status, if it is unlocked,
 * lock it and returns kStatus_OSA_Success, otherwise, timeout will be used for
 * wait. The parameter timeout indicates how long should wait in milliseconds.
 * Pass OSA_WAIT_FOREVER to wait indefinitely, pass 0 will return the value
 * kStatus_OSA_Timeout immediately if mutex is locked.
 * This function returns kStatus_OSA_Success if the mutex is obtained, returns
 * kStatus_OSA_Timeout if the mutex is not obtained within the specified
 * 'timeout', returns kStatus_OSA_Error if any errors occur during waiting.
 *
 *END**************************************************************************/
osa_status_t OSA_MutexLock(mutex_t *pMutex, uint32_t timeout)
{
    uint32_t timeoutTicks;

    assert(pMutex);

    /* If pMutex has been locked by current task, return error. */
    if (xSemaphoreGetMutexHolder(*pMutex) == xTaskGetCurrentTaskHandle())
    {
        return kStatus_OSA_Error;
    }

    /* Convert timeout from millisecond to tick. */
    if (timeout == OSA_WAIT_FOREVER)
    {
        timeoutTicks = portMAX_DELAY;
    }
    else
    {
        timeoutTicks = MSEC_TO_TICK(timeout);
    }

    if (xSemaphoreTake(*pMutex, timeoutTicks)==pdFALSE)
    {
        return kStatus_OSA_Timeout; /* timeout */
    }
    else
    {
        return kStatus_OSA_Success; /* semaphore taken */
    }
}
예제 #4
0
/*
 * Timeout function to reset the SCTP stack variable sctps_reclaim to false.
 */
static void
sctp_reclaim_timer(void *arg)
{
	sctp_stack_t *sctps = (sctp_stack_t *)arg;
	int64_t tot_assoc = 0;
	int i;
	extern pgcnt_t lotsfree, needfree;

	for (i = 0; i < sctps->sctps_sc_cnt; i++)
		tot_assoc += sctps->sctps_sc[i]->sctp_sc_assoc_cnt;

	/*
	 * This happens only when a stack is going away.  sctps_reclaim_tid
	 * should not be reset to 0 when returning in this case.
	 */
	mutex_enter(&sctps->sctps_reclaim_lock);
	if (!sctps->sctps_reclaim) {
		mutex_exit(&sctps->sctps_reclaim_lock);
		return;
	}

	if ((freemem >= lotsfree + needfree) || tot_assoc < maxusers) {
		sctps->sctps_reclaim = B_FALSE;
		sctps->sctps_reclaim_tid = 0;
	} else {
		/* Stay in defensive mode and restart the timer */
		sctps->sctps_reclaim_tid = timeout(sctp_reclaim_timer,
		    sctps, MSEC_TO_TICK(sctps->sctps_reclaim_period));
	}
	mutex_exit(&sctps->sctps_reclaim_lock);
}
예제 #5
0
/*FUNCTION**********************************************************************
 *
 * Function Name : OSA_MsgQGet
 * Description   : This function checks the queue's status, if it is not empty,
 * get message from it and return osaStatus_Success, otherwise, timeout will
 * be used for wait. The parameter timeout indicates how long should wait in
 * milliseconds. Pass osaWaitForever_c to wait indefinitely, pass 0 will return
 * osaStatus_Timeout immediately if queue is empty.
 * This function returns osaStatus_Success if message is got successfully,
 * returns osaStatus_Timeout if message queue is empty within the specified
 * 'timeout', returns osaStatus_Error if any errors occur during waiting.
 *
 *END**************************************************************************/
osaStatus_t OSA_MsgQGet(osaMsgQId_t msgQId, void *pMessage, uint32_t millisec)
{
#if osNumberOfMessageQs  
  osaStatus_t osaStatus;
  msg_queue_handler_t handler;
  uint32_t timeoutTicks;
  if( msgQId == NULL )
  {
    return osaStatus_Error;
  }
  handler = (msg_queue_handler_t)msgQId;
  if (millisec == osaWaitForever_c)
  {
    timeoutTicks = portMAX_DELAY;
  }
  else
  {
    timeoutTicks = MSEC_TO_TICK(millisec);
  }
  if (xQueueReceive(handler, pMessage, timeoutTicks)!=pdPASS)
  {
    osaStatus =  osaStatus_Timeout; /* not able to send it to the queue? */
  }
  else
  {
    osaStatus = osaStatus_Success;
  }
  return osaStatus;
#else
  (void)msgQId;
  (void)pMessage;
  (void)millisec;
  return osaStatus_Error;
#endif  
}
예제 #6
0
/*
 * Retry opens to avoid spurious sharing violations, due to timing
 * issues between closes and opens.  The client that already has the
 * file open may be in the process of closing it.
 */
uint32_t
smb_common_open(smb_request_t *sr)
{
	smb_arg_open_t	*parg;
	uint32_t	status = NT_STATUS_SUCCESS;
	int		count;

	parg = kmem_alloc(sizeof (*parg), KM_SLEEP);
	bcopy(&sr->arg.open, parg, sizeof (*parg));

	for (count = 0; count <= 4; count++) {
		if (count != 0)
			delay(MSEC_TO_TICK(400));

		status = smb_open_subr(sr);
		if (status != NT_STATUS_SHARING_VIOLATION)
			break;

		bcopy(parg, &sr->arg.open, sizeof (*parg));
	}

	if (status == NT_STATUS_SHARING_VIOLATION) {
		smbsr_error(sr, NT_STATUS_SHARING_VIOLATION,
		    ERRDOS, ERROR_SHARING_VIOLATION);
	}

	if (status == NT_STATUS_NO_SUCH_FILE) {
		smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
		    ERRDOS, ERROR_FILE_NOT_FOUND);
	}

	kmem_free(parg, sizeof (*parg));
	return (status);
}
/*FUNCTION**********************************************************************
 *
 * Function Name : OSA_TimeDelay
 * Description   : This function is used to delay for a number of milliseconds.
 *
 *END**************************************************************************/
void OSA_TimeDelay(uint32_t delay)
{
    delay = MSEC_TO_TICK(delay);
    /*
     * If delay is too short that changed to 0 tick, reset it to 1 tick
     * in case of no delay.
     */
    if (!delay)
    {
        delay = 1U;
    }
    OSTimeDly(delay);
}
예제 #8
0
//------------------------------------------------------------------------------
//
//  Function:  OALTimerUpdateRescheduleTime
//
//  This function is called by kernel to set next reschedule time.
//
VOID
OALTimerUpdateRescheduleTime(
    DWORD timeMSec
    )
{
    UINT32 baseMSec, periodMSec;
    INT32 delta;

    // Get current system timer counter
    baseMSec = CurMSec;

    // How far we are from next tick
    delta = (INT32)(g_oalTimerContext.match - OALTimerGetCount());

    if( delta < 0 )
    {
        UpdatePeriod(0);
        goto cleanUp;
    }

    // If timer interrupts occurs, or we are within 1 ms of the scheduled
    // interrupt, just return - timer ISR will take care of it.
    if ((baseMSec != CurMSec) || (delta < MSEC_TO_TICK(1))) goto cleanUp;

    // Calculate the distance between the new time and the last timer interrupt
      periodMSec = timeMSec - OEMGetTickCount();


    // Trying to set reschedule time prior or equal to CurMSec - this could
    // happen if a thread is on its way to sleep while preempted before
    // getting into the Sleep Queue
    if ((INT32)periodMSec < 0)
        {
        periodMSec = 0;
        }
    else if (periodMSec > g_oalTimerContext.maxPeriodMSec)
        {
        periodMSec = g_oalTimerContext.maxPeriodMSec;
        }

    // Now we find new period, so update timer
    UpdatePeriod(periodMSec);

cleanUp:
    return;
}
/*FUNCTION**********************************************************************
 *
 * Function Name : wait_timeout_msec_to_tick
 * Description   : This function converts timeout from millisecond to tick for
 * wait functions.
 *
 *END**************************************************************************/
static uint32_t wait_timeout_msec_to_tick(uint32_t timeout)
{
    if (OSA_WAIT_FOREVER == timeout)   /* Wait forever. */
    {
        return 0U; /* Timeout 0 means wait forever for uC/OS-II. */
    }
    else
    {
        timeout = MSEC_TO_TICK(timeout); /* Change timeout to tick. */
        /*
         * If timeout is too short that changed to 0 tick, reset it to 1 tick
         * in case of infinitely wait.
         */
        if (!timeout)
        {
            timeout = 1U;
        }
        return timeout;
    }
}
예제 #10
0
/*FUNCTION**********************************************************************
 *
 * Function Name : OSA_MutexLock
 * Description   : This function checks the mutex's status, if it is unlocked,
 * lock it and returns osaStatus_Success, otherwise, wait for the mutex.
 * This function returns osaStatus_Success if the mutex is obtained, returns
 * osaStatus_Error if any errors occur during waiting. If the mutex has been
 * locked, pass 0 as timeout will return osaStatus_Timeout immediately.
 *
 *END**************************************************************************/
osaStatus_t OSA_MutexLock(osaMutexId_t mutexId, uint32_t millisec)
{
#if osNumberOfMutexes    
    uint32_t timeoutTicks;
    mutex_t mutex = (mutex_t)mutexId;
    if(mutexId == NULL)
    {
     return osaStatus_Error;
    }
    /* If pMutex has been locked by current task, return error. */
    if (xSemaphoreGetMutexHolder(mutex) == xTaskGetCurrentTaskHandle())
    {
        return osaStatus_Error;
    }

    /* Convert timeout from millisecond to tick. */
    if (millisec == osaWaitForever_c)
    {
        timeoutTicks = portMAX_DELAY;
    }
    else
    {
        timeoutTicks = MSEC_TO_TICK(millisec);
    }

    if (xSemaphoreTake(mutex, timeoutTicks)==pdFALSE)
    {
        return osaStatus_Timeout; /* timeout */
    }
    else
    {
        return osaStatus_Success; /* semaphore taken */
    }
#else
    (void)mutexId;
    (void)millisec;  
    return osaStatus_Error;
#endif  
}
/*FUNCTION**********************************************************************
 *
 * Function Name : OSA_MsgQGet
 * Description   : This function checks the queue's status, if it is not empty,
 * get message from it and return kStatus_OSA_Success, otherwise, timeout will
 * be used for wait. The parameter timeout indicates how long should wait in
 * milliseconds. Pass OSA_WAIT_FOREVER to wait indefinitely, pass 0 will return
 * kStatus_OSA_Timeout immediately if queue is empty.
 * This function returns kStatus_OSA_Success if message is got successfully,
 * returns kStatus_OSA_Timeout if message queue is empty within the specified
 * 'timeout', returns kStatus_OSA_Error if any errors occur during waiting.
 *
 *END**************************************************************************/
osa_status_t OSA_MsgQGet(msg_queue_handler_t handler,
                           void               *pMessage,
                           uint32_t            timeout)
{
    uint32_t timeoutTicks;

    if (timeout == OSA_WAIT_FOREVER)
    {
        timeoutTicks = portMAX_DELAY;
    }
    else
    {
        timeoutTicks = MSEC_TO_TICK(timeout);
    }
    if (xQueueReceive(handler, pMessage, timeoutTicks)!=pdPASS)
    {
        return kStatus_OSA_Timeout; /* not able to send it to the queue? */
    }
    else
    {
        return kStatus_OSA_Success;
    }
}
/*FUNCTION**********************************************************************
 *
 * Function Name : OSA_SemaWait
 * Description   : This function checks the semaphore's counting value, if it is
 * positive, decreases it and returns kStatus_OSA_Success, otherwise, timeout
 * will be used for wait. The parameter timeout indicates how long should wait
 * in milliseconds. Pass OSA_WAIT_FOREVER to wait indefinitely, pass 0 will
 * return kStatus_OSA_Timeout immediately if semaphore is not positive.
 * This function returns kStatus_OSA_Success if the semaphore is received, returns
 * kStatus_OSA_Timeout if the semaphore is not received within the specified
 * 'timeout', returns kStatus_OSA_Error if any errors occur during waiting.
 *
 *END**************************************************************************/
osa_status_t OSA_SemaWait(semaphore_t *pSem, uint32_t timeout)
{
    uint32_t timeoutTicks;
    assert(pSem);

    /* Convert timeout from millisecond to tick. */
    if (timeout == OSA_WAIT_FOREVER)
    {
        timeoutTicks = portMAX_DELAY;
    }
    else
    {
        timeoutTicks = MSEC_TO_TICK(timeout);
    }

    if (xSemaphoreTake(*pSem, timeoutTicks)==pdFALSE)
    {
        return kStatus_OSA_Timeout; /* timeout */
    }
    else
    {
        return kStatus_OSA_Success; /* semaphore taken */
    }
}
예제 #13
0
/*
 * mac_soft_ring_create
 *
 * Create a soft ring, do the necessary setup and bind the worker
 * thread to the assigned CPU.
 */
mac_soft_ring_t *
mac_soft_ring_create(int id, clock_t wait, void *flent, uint16_t type,
    pri_t pri, mac_client_impl_t *mcip, mac_soft_ring_set_t *mac_srs,
    processorid_t cpuid, mac_direct_rx_t rx_func, void *x_arg1,
    mac_resource_handle_t x_arg2)
{
	mac_soft_ring_t 	*ringp;
	char 			name[S_RING_NAMELEN];

	bzero(name, 64);
	ringp = kmem_cache_alloc(mac_soft_ring_cache, KM_SLEEP);

	if (type & ST_RING_TCP) {
		(void) snprintf(name, sizeof (name),
		    "mac_tcp_soft_ring_%d_%p", id, (void *)mac_srs);
	} else if (type & ST_RING_UDP) {
		(void) snprintf(name, sizeof (name),
		    "mac_udp_soft_ring_%d_%p", id, (void *)mac_srs);
	} else {
		(void) snprintf(name, sizeof (name),
		    "mac_oth_soft_ring_%d_%p", id, (void *)mac_srs);
	}

	bzero(ringp, sizeof (mac_soft_ring_t));
	(void) strncpy(ringp->s_ring_name, name, S_RING_NAMELEN + 1);
	ringp->s_ring_name[S_RING_NAMELEN] = '\0';
	mutex_init(&ringp->s_ring_lock, NULL, MUTEX_DEFAULT, NULL);
	ringp->s_ring_notify_cb_info.mcbi_lockp = &ringp->s_ring_lock;

	ringp->s_ring_type = type;
	ringp->s_ring_wait = MSEC_TO_TICK(wait);
	ringp->s_ring_mcip = mcip;
	ringp->s_ring_set = mac_srs;
	ringp->s_ring_flent = flent;

	/*
	 * Protect against access from DR callbacks (mac_walk_srs_bind/unbind)
	 * which can't grab the mac perimeter
	 */
	mutex_enter(&mac_srs->srs_lock);
	ADD_SOFTRING_TO_SET(mac_srs, ringp);
	mutex_exit(&mac_srs->srs_lock);

	/*
	 * set the bind CPU to -1 to indicate
	 * no thread affinity set
	 */
	ringp->s_ring_cpuid = ringp->s_ring_cpuid_save = -1;
	ringp->s_ring_worker = thread_create(NULL, 0,
	    mac_soft_ring_worker, ringp, 0, &p0, TS_RUN, pri);
	if (type & ST_RING_TX) {
		ringp->s_ring_drain_func = mac_tx_soft_ring_drain;
		ringp->s_ring_tx_arg1 = x_arg1;
		ringp->s_ring_tx_arg2 = x_arg2;
		ringp->s_ring_tx_max_q_cnt = mac_tx_soft_ring_max_q_cnt;
		ringp->s_ring_tx_hiwat =
		    (mac_tx_soft_ring_hiwat > mac_tx_soft_ring_max_q_cnt) ?
		    mac_tx_soft_ring_max_q_cnt : mac_tx_soft_ring_hiwat;
	} else {
		ringp->s_ring_drain_func = mac_rx_soft_ring_drain;
		ringp->s_ring_rx_func = rx_func;
		ringp->s_ring_rx_arg1 = x_arg1;
		ringp->s_ring_rx_arg2 = x_arg2;
		if (mac_srs->srs_state & SRS_SOFTRING_QUEUE)
			ringp->s_ring_type |= ST_RING_WORKER_ONLY;
	}
	if (cpuid != -1)
		(void) mac_soft_ring_bind(ringp, cpuid);

	return (ringp);
}
예제 #14
0
/*
 * Add a connection to the list of detached TIME_WAIT connections
 * and set its time to expire.
 */
void
tcp_time_wait_append(tcp_t *tcp)
{
	tcp_stack_t	*tcps = tcp->tcp_tcps;
	squeue_t	*sqp = tcp->tcp_connp->conn_sqp;
	tcp_squeue_priv_t *tcp_time_wait =
	    *((tcp_squeue_priv_t **)squeue_getprivate(sqp, SQPRIVATE_TCP));

	tcp_timers_stop(tcp);

	/* Freed above */
	ASSERT(tcp->tcp_timer_tid == 0);
	ASSERT(tcp->tcp_ack_tid == 0);

	/* must have happened at the time of detaching the tcp */
	ASSERT(tcp->tcp_ptpahn == NULL);
	ASSERT(tcp->tcp_flow_stopped == 0);
	ASSERT(tcp->tcp_time_wait_next == NULL);
	ASSERT(tcp->tcp_time_wait_prev == NULL);
	ASSERT(tcp->tcp_time_wait_expire == 0);
	ASSERT(tcp->tcp_listener == NULL);

	tcp->tcp_time_wait_expire = ddi_get_lbolt64();
	/*
	 * Since tcp_time_wait_expire is lbolt64, it should not wrap around
	 * in practice.  Hence it cannot be 0.  Note that zero means that the
	 * tcp_t is not in the TIME_WAIT list.
	 */
	tcp->tcp_time_wait_expire += MSEC_TO_TICK(
	    tcps->tcps_time_wait_interval);

	ASSERT(TCP_IS_DETACHED(tcp));
	ASSERT(tcp->tcp_state == TCPS_TIME_WAIT);
	ASSERT(tcp->tcp_time_wait_next == NULL);
	ASSERT(tcp->tcp_time_wait_prev == NULL);
	TCP_DBGSTAT(tcps, tcp_time_wait);

	mutex_enter(&tcp_time_wait->tcp_time_wait_lock);
	if (tcp_time_wait->tcp_time_wait_head == NULL) {
		ASSERT(tcp_time_wait->tcp_time_wait_tail == NULL);
		tcp_time_wait->tcp_time_wait_head = tcp;

		/*
		 * Even if the list was empty before, there may be a timer
		 * running since a tcp_t can be removed from the list
		 * in other places, such as tcp_clean_death().  So check if
		 * a timer is needed.
		 */
		if (tcp_time_wait->tcp_time_wait_tid == 0) {
			tcp_time_wait->tcp_time_wait_tid =
			    timeout_generic(CALLOUT_NORMAL,
			    tcp_time_wait_collector, sqp,
			    (hrtime_t)(tcps->tcps_time_wait_interval + 1) *
			    MICROSEC, CALLOUT_TCP_RESOLUTION,
			    CALLOUT_FLAG_ROUNDUP);
		}
	} else {
		/*
		 * The list is not empty, so a timer must be running.  If not,
		 * tcp_time_wait_collector() must be running on this
		 * tcp_time_wait list at the same time.
		 */
		ASSERT(tcp_time_wait->tcp_time_wait_tid != 0 ||
		    tcp_time_wait->tcp_time_wait_running);
		ASSERT(tcp_time_wait->tcp_time_wait_tail != NULL);
		ASSERT(tcp_time_wait->tcp_time_wait_tail->tcp_state ==
		    TCPS_TIME_WAIT);
		tcp_time_wait->tcp_time_wait_tail->tcp_time_wait_next = tcp;
		tcp->tcp_time_wait_prev = tcp_time_wait->tcp_time_wait_tail;

	}
	tcp_time_wait->tcp_time_wait_tail = tcp;
	mutex_exit(&tcp_time_wait->tcp_time_wait_lock);
}
예제 #15
0
smb_sdrc_t
smb_com_echo(struct smb_request *sr)
{
	unsigned short necho;
	unsigned short nbytes;
	unsigned short i;
	struct mbuf_chain reply;
	char *data;
	uint16_t	pid_hi, pid_lo;

	pid_hi = sr->smb_pid >> 16;
	pid_lo = (uint16_t)sr->smb_pid;

	if (smbsr_decode_vwv(sr, "w", &necho) != 0)
		return (SDRC_ERROR);

	/*
	 * Don't let the client fool us into doing
	 * more work than is "reasonable".
	 */
	if (necho > smb_max_echo)
		necho = smb_max_echo;

	nbytes = sr->smb_bcc;
	data = smb_srm_zalloc(sr, nbytes);

	if (smb_mbc_decodef(&sr->smb_data, "#c", nbytes, data))
		return (SDRC_ERROR);

	for (i = 1; i <= necho; ++i) {

		/*
		 * According to [MS-CIFS] 3.3.5.32 echo is
		 * subject to cancellation.
		 */
		if (sr->sr_state != SMB_REQ_STATE_ACTIVE)
			break;

		MBC_INIT(&reply, SMB_HEADER_ED_LEN + 10 + nbytes);

		(void) smb_mbc_encodef(&reply, SMB_HEADER_ED_FMT,
		    sr->first_smb_com,
		    sr->smb_rcls,
		    sr->smb_reh,
		    sr->smb_err,
		    sr->smb_flg | SMB_FLAGS_REPLY,
		    sr->smb_flg2,
		    pid_hi,
		    sr->smb_sig,
		    sr->smb_tid,
		    pid_lo,
		    sr->smb_uid,
		    sr->smb_mid);

		(void) smb_mbc_encodef(&reply, "bww#c", 1, i,
		    nbytes, nbytes, data);

		if (sr->session->signing.flags & SMB_SIGNING_ENABLED)
			smb_sign_reply(sr, &reply);

		(void) smb_session_send(sr->session, 0, &reply);

		delay(MSEC_TO_TICK(100));
	}

	return (SDRC_NO_REPLY);
}
예제 #16
0
/* ARGSUSED */
void
sctp_conn_reclaim(void *arg)
{
	netstack_handle_t nh;
	netstack_t *ns;
	sctp_stack_t *sctps;
	extern pgcnt_t lotsfree, needfree;

	if (!sctp_do_reclaim)
		return;

	/*
	 * The reclaim function may be called even when the system is not
	 * really under memory pressure.
	 */
	if (freemem >= lotsfree + needfree)
		return;

	netstack_next_init(&nh);
	while ((ns = netstack_next(&nh)) != NULL) {
		int i;
		int64_t tot_assoc = 0;

		/*
		 * During boot time, the first netstack_t is created and
		 * initialized before SCTP has registered with the netstack
		 * framework.  If this reclaim function is called before SCTP
		 * has finished its initialization, netstack_next() will
		 * return the first netstack_t (since its netstack_flags is
		 * not NSF_UNINIT).  And its netstack_sctp will be NULL.  We
		 * need to catch it.
		 *
		 * All subsequent netstack_t creation will not have this
		 * problem since the initialization is not finished until SCTP
		 * has finished its own sctp_stack_t initialization.  Hence
		 * netstack_next() will not return one with NULL netstack_sctp.
		 */
		if ((sctps = ns->netstack_sctp) == NULL) {
			netstack_rele(ns);
			continue;
		}

		/*
		 * Even if the system is under memory pressure, the reason may
		 * not be because of SCTP activity.  Check the number of
		 * associations in each stack.  If the number exceeds the
		 * threshold (maxusers), turn on defensive mode.
		 */
		for (i = 0; i < sctps->sctps_sc_cnt; i++)
			tot_assoc += sctps->sctps_sc[i]->sctp_sc_assoc_cnt;
		if (tot_assoc < maxusers) {
			netstack_rele(ns);
			continue;
		}

		mutex_enter(&sctps->sctps_reclaim_lock);
		if (!sctps->sctps_reclaim) {
			sctps->sctps_reclaim = B_TRUE;
			sctps->sctps_reclaim_tid = timeout(sctp_reclaim_timer,
			    sctps, MSEC_TO_TICK(sctps->sctps_reclaim_period));
			SCTP_KSTAT(sctps, sctp_reclaim_cnt);
		}
		mutex_exit(&sctps->sctps_reclaim_lock);
		netstack_rele(ns);
	}
	netstack_next_fini(&nh);
}
예제 #17
0
/*
 * Call this function to get information about a peer addr fp.
 *
 * Uses ip_attr_connect to avoid explicit use of ire and source address
 * selection.
 */
void
sctp_get_dest(sctp_t *sctp, sctp_faddr_t *fp)
{
	in6_addr_t	laddr;
	in6_addr_t	nexthop;
	sctp_saddr_ipif_t *sp;
	int		hdrlen;
	sctp_stack_t	*sctps = sctp->sctp_sctps;
	conn_t		*connp = sctp->sctp_connp;
	iulp_t		uinfo;
	uint_t		pmtu;
	int		error;
	uint32_t	flags = IPDF_VERIFY_DST | IPDF_IPSEC |
	    IPDF_SELECT_SRC | IPDF_UNIQUE_DCE;

	/*
	 * Tell sctp_make_mp it needs to call us again should we not
	 * complete and set the saddr.
	 */
	fp->saddr = ipv6_all_zeros;

	/*
	 * If this addr is not reachable, mark it as unconfirmed for now, the
	 * state will be changed back to unreachable later in this function
	 * if it is still the case.
	 */
	if (fp->state == SCTP_FADDRS_UNREACH) {
		fp->state = SCTP_FADDRS_UNCONFIRMED;
	}

	/*
	 * Socket is connected - enable PMTU discovery.
	 */
	if (!sctps->sctps_ignore_path_mtu)
		fp->ixa->ixa_flags |= IXAF_PMTU_DISCOVERY;

	ip_attr_nexthop(&connp->conn_xmit_ipp, fp->ixa, &fp->faddr,
	    &nexthop);

	laddr = fp->saddr;
	error = ip_attr_connect(connp, fp->ixa, &laddr, &fp->faddr, &nexthop,
	    connp->conn_fport, &laddr, &uinfo, flags);

	if (error != 0) {
		dprint(3, ("sctp_get_dest: no ire for %x:%x:%x:%x\n",
		    SCTP_PRINTADDR(fp->faddr)));
		/*
		 * It is tempting to just leave the src addr
		 * unspecified and let IP figure it out, but we
		 * *cannot* do this, since IP may choose a src addr
		 * that is not part of this association... unless
		 * this sctp has bound to all addrs.  So if the dest
		 * lookup fails, try to find one in our src addr
		 * list, unless the sctp has bound to all addrs, in
		 * which case we change the src addr to unspec.
		 *
		 * Note that if this is a v6 endpoint but it does
		 * not have any v4 address at this point (e.g. may
		 * have been  deleted), sctp_get_valid_addr() will
		 * return mapped INADDR_ANY.  In this case, this
		 * address should be marked not reachable so that
		 * it won't be used to send data.
		 */
		sctp_set_saddr(sctp, fp);
		if (fp->state == SCTP_FADDRS_UNREACH)
			return;
		goto check_current;
	}
	ASSERT(fp->ixa->ixa_ire != NULL);
	ASSERT(!(fp->ixa->ixa_ire->ire_flags & (RTF_REJECT|RTF_BLACKHOLE)));

	if (!sctp->sctp_loopback)
		sctp->sctp_loopback = uinfo.iulp_loopback;

	/* Make sure the laddr is part of this association */
	if ((sp = sctp_saddr_lookup(sctp, &laddr, 0)) != NULL &&
	    !sp->saddr_ipif_dontsrc) {
		if (sp->saddr_ipif_unconfirmed == 1)
			sp->saddr_ipif_unconfirmed = 0;
		/* We did IPsec policy lookup for laddr already */
		fp->saddr = laddr;
	} else {
		dprint(2, ("sctp_get_dest: src addr is not part of assoc "
		    "%x:%x:%x:%x\n", SCTP_PRINTADDR(laddr)));

		/*
		 * Set the src to the first saddr and hope for the best.
		 * Note that this case should very seldomly
		 * happen.  One scenario this can happen is an app
		 * explicitly bind() to an address.  But that address is
		 * not the preferred source address to send to the peer.
		 */
		sctp_set_saddr(sctp, fp);
		if (fp->state == SCTP_FADDRS_UNREACH) {
			return;
		}
	}

	/*
	 * Pull out RTO information for this faddr and use it if we don't
	 * have any yet.
	 */
	if (fp->srtt == -1 && uinfo.iulp_rtt != 0) {
		/* The cached value is in ms. */
		fp->srtt = MSEC_TO_TICK(uinfo.iulp_rtt);
		fp->rttvar = MSEC_TO_TICK(uinfo.iulp_rtt_sd);
		fp->rto = 3 * fp->srtt;

		/* Bound the RTO by configured min and max values */
		if (fp->rto < sctp->sctp_rto_min) {
			fp->rto = sctp->sctp_rto_min;
		}
		if (fp->rto > sctp->sctp_rto_max) {
			fp->rto = sctp->sctp_rto_max;
		}
		SCTP_MAX_RTO(sctp, fp);
	}
	pmtu = uinfo.iulp_mtu;

	/*
	 * Record the MTU for this faddr. If the MTU for this faddr has
	 * changed, check if the assc MTU will also change.
	 */
	if (fp->isv4) {
		hdrlen = sctp->sctp_hdr_len;
	} else {
		hdrlen = sctp->sctp_hdr6_len;
	}
	if ((fp->sfa_pmss + hdrlen) != pmtu) {
		/* Make sure that sfa_pmss is a multiple of SCTP_ALIGN. */
		fp->sfa_pmss = (pmtu - hdrlen) & ~(SCTP_ALIGN - 1);
		if (fp->cwnd < (fp->sfa_pmss * 2)) {
			SET_CWND(fp, fp->sfa_pmss,
			    sctps->sctps_slow_start_initial);
		}
	}

check_current:
	if (fp == sctp->sctp_current)
		sctp_set_faddr_current(sctp, fp);
}
/*FUNCTION**********************************************************************
 *
 * Function Name : OSA_TimeDelay
 * Description   : This function is used to delay for a number of milliseconds.
 *
 *END**************************************************************************/
void OSA_TimeDelay(uint32_t delay)
{
    vTaskDelay(MSEC_TO_TICK(delay));
}
예제 #19
0
/*
 * smb_rename_lookup_src
 *
 * Lookup the src node, checking for sharing violations and
 * breaking any existing BATCH oplock.
 * Populate sr->arg.dirop.fqi
 *
 * Upon success, the dnode and fnode will have holds and the
 * fnode will be in a critical section. These should be
 * released using smb_rename_release_src().
 *
 * Returns errno values.
 */
static int
smb_rename_lookup_src(smb_request_t *sr)
{
	smb_node_t *src_node, *tnode;
	DWORD status;
	int rc;
	int count;
	char *path;

	smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;

	if (smb_is_stream_name(src_fqi->fq_path.pn_path))
		return (EINVAL);

	/* Lookup the source node */
	tnode = sr->tid_tree->t_snode;
	path = src_fqi->fq_path.pn_path;
	rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
	    &src_fqi->fq_dnode, src_fqi->fq_last_comp);
	if (rc != 0)
		return (rc);

	rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode,
	    src_fqi->fq_dnode, src_fqi->fq_last_comp, &src_fqi->fq_fnode);
	if (rc != 0) {
		smb_node_release(src_fqi->fq_dnode);
		return (rc);
	}
	src_node = src_fqi->fq_fnode;

	rc = smb_rename_check_attr(sr, src_node, src_fqi->fq_sattr);
	if (rc != 0) {
		smb_node_release(src_fqi->fq_fnode);
		smb_node_release(src_fqi->fq_dnode);
		return (rc);
	}

	/*
	 * Break BATCH oplock before ofile checks. If a client
	 * has a file open, this will force a flush or close,
	 * which may affect the outcome of any share checking.
	 */
	(void) smb_oplock_break(sr, src_node,
	    SMB_OPLOCK_BREAK_TO_LEVEL_II | SMB_OPLOCK_BREAK_BATCH);

	/*
	 * Wait (a little) for the oplock break to be
	 * responded to by clients closing handles.
	 * Hold node->n_lock as reader to keep new
	 * ofiles from showing up after we check.
	 */
	smb_node_rdlock(src_node);
	for (count = 0; count <= 12; count++) {
		status = smb_node_rename_check(src_node);
		if (status != NT_STATUS_SHARING_VIOLATION)
			break;
		smb_node_unlock(src_node);
		delay(MSEC_TO_TICK(100));
		smb_node_rdlock(src_node);
	}
	if (status != NT_STATUS_SUCCESS) {
		smb_node_unlock(src_node);
		smb_node_release(src_fqi->fq_fnode);
		smb_node_release(src_fqi->fq_dnode);
		return (EPIPE); /* = ERRbadshare */
	}

	/*
	 * Note, the combination of these two:
	 *	smb_node_rdlock(node);
	 *	nbl_start_crit(node->vp, RW_READER);
	 * is equivalent to this call:
	 *	smb_node_start_crit(node, RW_READER)
	 *
	 * Cleanup after this point should use:
	 *	smb_node_end_crit(src_node)
	 */
	nbl_start_crit(src_node->vp, RW_READER);

	/*
	 * This checks nbl_share_conflict, nbl_lock_conflict
	 */
	status = smb_nbl_conflict(src_node, 0, UINT64_MAX, NBL_RENAME);
	if (status != NT_STATUS_SUCCESS) {
		smb_node_end_crit(src_node);
		smb_node_release(src_fqi->fq_fnode);
		smb_node_release(src_fqi->fq_dnode);
		if (status == NT_STATUS_SHARING_VIOLATION)
			return (EPIPE); /* = ERRbadshare */
		return (EACCES);
	}

	/* NB: Caller expects holds on src_fqi fnode, dnode */
	return (0);
}
예제 #20
0
파일: condvar.c 프로젝트: BjoKaSH/mac-zfs
/*
 * Same as cv_wait(), but wakes up (after wakeup_time milliseconds) to check
 * for requests to stop, like cv_wait_sig() but without dealing with signals.
 * This is a horrible kludge.  It is evil.  It is vile.  It is swill.
 * If your code has to call this function then your code is the same.
 */
void
cv_wait_stop(kcondvar_t *cvp, kmutex_t *mp, int wakeup_time)
{
	kthread_t *t = curthread;
	klwp_t *lwp = ttolwp(t);
	proc_t *p = ttoproc(t);
	timeout_id_t id;
	clock_t tim;

	if (panicstr)
		return;

	/*
	 * If there is no lwp, then we don't need to eventually stop it
	 * The check for t_intr is to catch an interrupt thread
	 * that has not yet unpinned the thread underneath.
	 */
	if (lwp == NULL || t->t_intr) {
		cv_wait(cvp, mp);
		return;
	}

	/*
	 * Wakeup in wakeup_time milliseconds, i.e., human time.
	 */
	tim = lbolt + MSEC_TO_TICK(wakeup_time);
	id = realtime_timeout((void (*)(void *))setrun, t, tim - lbolt);
	thread_lock(t);			/* lock the thread */
	cv_block((condvar_impl_t *)cvp);
	thread_unlock_nopreempt(t);
	mutex_exit(mp);
	/* ASSERT(no locks are held); */
	if ((tim - lbolt) <= 0)		/* allow for wrap */
		setrun(t);
	swtch();
	(void) untimeout(id);

	/*
	 * Check for reasons to stop, if lwp_nostop is not true.
	 * See issig_forreal() for explanations of the various stops.
	 */
	mutex_enter(&p->p_lock);
	while (lwp->lwp_nostop == 0 && !(p->p_flag & SEXITLWPS)) {
		/*
		 * Hold the lwp here for watchpoint manipulation.
		 */
		if (t->t_proc_flag & TP_PAUSE) {
			stop(PR_SUSPENDED, SUSPEND_PAUSE);
			continue;
		}
		/*
		 * System checkpoint.
		 */
		if (t->t_proc_flag & TP_CHKPT) {
			stop(PR_CHECKPOINT, 0);
			continue;
		}
		/*
		 * Honor fork1(), watchpoint activity (remapping a page),
		 * and lwp_suspend() requests.
		 */
		if ((p->p_flag & (SHOLDFORK1|SHOLDWATCH)) ||
		    (t->t_proc_flag & TP_HOLDLWP)) {
			stop(PR_SUSPENDED, SUSPEND_NORMAL);
			continue;
		}
		/*
		 * Honor /proc requested stop.
		 */
		if (t->t_proc_flag & TP_PRSTOP) {
			stop(PR_REQUESTED, 0);
		}
		/*
		 * If some lwp in the process has already stopped
		 * showing PR_JOBCONTROL, stop in sympathy with it.
		 */
		if (p->p_stopsig && t != p->p_agenttp) {
			stop(PR_JOBCONTROL, p->p_stopsig);
			continue;
		}
		break;
	}
	mutex_exit(&p->p_lock);
	mutex_enter(mp);
}
예제 #21
0
//------------------------------------------------------------------------------
//
//  Function: OALTimerInit
//
//  General purpose timer 1 is used for system tick. It supports
//  count/compare mode on 32kHz clock
//
BOOL
OALTimerInit(
    UINT32 sysTickMSec,
    UINT32 countsPerMSec,
    UINT32 countsMargin
    )
{
    BOOL rc = FALSE;
    UINT srcClock;
    UINT32 sysIntr;

	UNREFERENCED_PARAMETER(sysTickMSec);
	UNREFERENCED_PARAMETER(countsPerMSec);
	UNREFERENCED_PARAMETER(countsMargin);

    OALMSG(1&&OAL_FUNC, (L"+OALTimerInit(%d, %d, %d)\r\n", sysTickMSec, countsPerMSec, countsMargin ));

    //  Initialize timer state information
    g_oalTimerContext.maxPeriodMSec = dwOEMMaxIdlePeriod;   // Maximum period the timer will interrupt on, in mSec
    g_oalTimerContext.margin =        DELTA_TIME;           // Time needed to reprogram the timer interrupt
    g_oalTimerContext.curCounts =     0;
    g_oalTimerContext.base =          0;
    g_oalTimerContext.match =         0xFFFFFFFF;
    g_oalTimerContext.Posted =       0;

    // Set idle conversion constant and counters
    idleconv     = MSEC_TO_TICK(1);
    curridlehigh = 0;
    curridlelow  = 0;

    // Use variable system tick
    pOEMUpdateRescheduleTime = OALTimerUpdateRescheduleTime;

	// Get virtual addresses for hardware
    g_TimerDevice = BSPGetSysTimerDevice(); // OMAP_DEVICE_GPTIMER1
    
    g_pTimerRegs = OALPAtoUA(GetAddressByDevice(g_TimerDevice));
	OALMSG(1 && OAL_FUNC, (L" TimerPA: 0x%x\r\n", GetAddressByDevice(g_TimerDevice)));
	OALMSG(1 && OAL_FUNC, (L" TimerUA: 0x%x\r\n", g_pTimerRegs));
	// Select 32K frequency source clock
    srcClock = BSPGetSysTimer32KClock(); // k32K_FCLK
    
	//PrcmDeviceSetSourceClocks(g_TimerDevice,1,&srcClock);

    // enable gptimer
    EnableDeviceClocks(g_TimerDevice, TRUE);


    // stop timer
    OALTimerSetReg(&g_pTimerRegs->TCLR, 0);

    // Soft reset GPTIMER
    OALTimerSetReg(&g_pTimerRegs->TIOCP, SYSCONFIG_SOFTRESET);

    // While until done
    while ((OALTimerGetReg(&g_pTimerRegs->TISTAT) & GPTIMER_TISTAT_RESETDONE) == 0);

    // Set smart idle
    OALTimerSetReg(
        &g_pTimerRegs->TIOCP,
            SYSCONFIG_SMARTIDLE|SYSCONFIG_ENAWAKEUP|
            SYSCONFIG_AUTOIDLE
        );

    // Enable posted mode
    OALTimerSetReg(&g_pTimerRegs->TSICR, GPTIMER_TSICR_POSTED);
    g_oalTimerContext.Posted =       1;

    // Set match register to avoid unwanted interrupt
    OALTimerSetReg(&g_pTimerRegs->TMAR, 0xFFFFFFFF);

    // Enable match interrupt
    OALTimerSetReg(&g_pTimerRegs->TIER, GPTIMER_TIER_MATCH);

    // Enable match wakeup
    OALTimerSetReg(&g_pTimerRegs->TWER, GPTIMER_TWER_MATCH);

    // Enable timer in auto-reload and compare mode
    OALTimerSetReg(&g_pTimerRegs->TCLR, GPTIMER_TCLR_CE|GPTIMER_TCLR_AR|GPTIMER_TCLR_ST);

    // Wait until write is done
    //while ((INREG32(&g_pTimerRegs->TWPS) & GPTIMER_TWPS_TCLR) != 0);

    // Set global variable to tell interrupt module about timer used
    g_oalTimerIrq = GetIrqByDevice(g_TimerDevice,NULL); // 37

    // Request SYSINTR for timer IRQ, it is done to reserve it...
    sysIntr = OALIntrRequestSysIntr(1, &g_oalTimerIrq, OAL_INTR_FORCE_STATIC); // 17

    // Enable System Tick interrupt
    if (!OEMInterruptEnable(sysIntr, NULL, 0))
        {
        OALMSG(OAL_ERROR, (
            L"ERROR: OALTimerInit: Interrupt enable for system timer failed"
            ));
        goto cleanUp;
        }

    // Initialize timer to maximum period
    UpdatePeriod(g_oalTimerContext.maxPeriodMSec);

    // Done
    rc = TRUE;

cleanUp:
    OALMSG(1 && OAL_FUNC, (L"-OALTimerInit(rc = %d)\r\n", rc));
    return rc;
}
예제 #22
0
/*
 * smb_common_rename
 *
 * Common code for renaming a file.
 *
 * If the source and destination are identical, we go through all
 * the checks but we don't actually do the rename.  If the source
 * and destination files differ only in case, we do a case-sensitive
 * rename.  Otherwise, we do a full case-insensitive rename.
 *
 * Returns NT status values.
 *
 * Similar to smb_make_link(), below.
 */
uint32_t
smb_common_rename(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
{
	smb_node_t *src_fnode, *src_dnode, *dst_dnode;
	smb_node_t *dst_fnode = 0;
	smb_node_t *tnode;
	char *new_name, *path;
	DWORD status;
	int rc, count;

	tnode = sr->tid_tree->t_snode;
	path = dst_fqi->fq_path.pn_path;

	/* Check if attempting to rename a stream - not yet supported */
	rc = smb_rename_check_stream(src_fqi, dst_fqi);
	if (rc != 0)
		return (smb_rename_errno2status(rc));

	/*
	 * The source node may already have been provided,
	 * i.e. when called by SMB1/SMB2 smb_setinfo_rename.
	 * Not provided by smb_com_rename, smb_com_nt_rename.
	 */
	if (src_fqi->fq_fnode) {
		smb_node_start_crit(src_fqi->fq_fnode, RW_READER);
		smb_node_ref(src_fqi->fq_fnode);
		smb_node_ref(src_fqi->fq_dnode);
	} else {
		/* lookup and validate src node */
		rc = smb_rename_lookup_src(sr);
		if (rc != 0)
			return (smb_rename_errno2status(rc));
	}

	src_fnode = src_fqi->fq_fnode;
	src_dnode = src_fqi->fq_dnode;

	/*
	 * Find the destination dnode and last component.
	 * May already be provided, i.e. when called via
	 * SMB1 trans2 setinfo.
	 */
	if (dst_fqi->fq_dnode) {
		/* called via smb_set_rename_info */
		smb_node_ref(dst_fqi->fq_dnode);
	} else {
		/* called via smb2_setf_rename, smb_com_rename, etc. */
		rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
		    &dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
		if (rc != 0) {
			smb_rename_release_src(sr);
			return (smb_rename_errno2status(rc));
		}
	}

	dst_dnode = dst_fqi->fq_dnode;
	new_name = dst_fqi->fq_last_comp;

	/* If exact name match in same directory, we're done */
	if ((src_dnode == dst_dnode) &&
	    (strcmp(src_fnode->od_name, new_name) == 0)) {
		smb_rename_release_src(sr);
		smb_node_release(dst_dnode);
		return (0);
	}

	/* Lookup destination node */
	rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode,
	    dst_dnode, new_name, &dst_fqi->fq_fnode);

	/* If the destination node doesn't already exist, validate new_name. */
	if (rc == ENOENT) {
		if (smb_is_invalid_filename(new_name)) {
			smb_rename_release_src(sr);
			smb_node_release(dst_dnode);
			return (NT_STATUS_OBJECT_NAME_INVALID);
		}
	}

	/*
	 * Handle case where changing case of the same directory entry.
	 *
	 * If we found the dst node in the same directory as the src node,
	 * and their names differ only in case:
	 *
	 * If the tree is case sensitive (or mixed):
	 *  Do case sensitive lookup to see if exact match exists.
	 *  If the exact match is the same node as src_node we're done.
	 *
	 * If the tree is case insensitive:
	 *  There is currently no way to tell if the case is different
	 *  or not, so do the rename (unless the specified new name was
	 *  mangled).
	 */
	if ((rc == 0) &&
	    (src_dnode == dst_dnode) &&
	    (smb_strcasecmp(src_fnode->od_name,
	    dst_fqi->fq_fnode->od_name, 0) == 0)) {
		smb_node_release(dst_fqi->fq_fnode);
		dst_fqi->fq_fnode = NULL;

		if (smb_tree_has_feature(sr->tid_tree,
		    SMB_TREE_NO_CASESENSITIVE)) {
			if (smb_strcasecmp(src_fnode->od_name,
			    dst_fqi->fq_last_comp, 0) != 0) {
				smb_rename_release_src(sr);
				smb_node_release(dst_dnode);
				return (0);
			}
		} else {
			rc = smb_fsop_lookup(sr, sr->user_cr,
			    SMB_CASE_SENSITIVE, tnode, dst_dnode, new_name,
			    &dst_fqi->fq_fnode);

			if ((rc == 0) &&
			    (dst_fqi->fq_fnode == src_fnode)) {
				smb_rename_release_src(sr);
				smb_node_release(dst_fqi->fq_fnode);
				smb_node_release(dst_dnode);
				return (0);
			}
		}
	}

	if ((rc != 0) && (rc != ENOENT)) {
		smb_rename_release_src(sr);
		smb_node_release(dst_fqi->fq_dnode);
		return (smb_rename_errno2status(rc));
	}

	if (dst_fqi->fq_fnode) {
		/*
		 * Destination already exists.  Do delete checks.
		 */
		dst_fnode = dst_fqi->fq_fnode;

		if (!(sr->arg.dirop.flags && SMB_RENAME_FLAG_OVERWRITE)) {
			smb_rename_release_src(sr);
			smb_node_release(dst_fnode);
			smb_node_release(dst_dnode);
			return (NT_STATUS_OBJECT_NAME_COLLISION);
		}

		(void) smb_oplock_break(sr, dst_fnode,
		    SMB_OPLOCK_BREAK_TO_NONE | SMB_OPLOCK_BREAK_BATCH);

		/*
		 * Wait (a little) for the oplock break to be
		 * responded to by clients closing handles.
		 * Hold node->n_lock as reader to keep new
		 * ofiles from showing up after we check.
		 */
		smb_node_rdlock(dst_fnode);
		for (count = 0; count <= 12; count++) {
			status = smb_node_delete_check(dst_fnode);
			if (status != NT_STATUS_SHARING_VIOLATION)
				break;
			smb_node_unlock(dst_fnode);
			delay(MSEC_TO_TICK(100));
			smb_node_rdlock(dst_fnode);
		}
		if (status != NT_STATUS_SUCCESS) {
			smb_node_unlock(dst_fnode);
			smb_rename_release_src(sr);
			smb_node_release(dst_fnode);
			smb_node_release(dst_dnode);
			return (NT_STATUS_ACCESS_DENIED);
		}

		/*
		 * Note, the combination of these two:
		 *	smb_node_rdlock(node);
		 *	nbl_start_crit(node->vp, RW_READER);
		 * is equivalent to this call:
		 *	smb_node_start_crit(node, RW_READER)
		 *
		 * Cleanup after this point should use:
		 *	smb_node_end_crit(dst_fnode)
		 */
		nbl_start_crit(dst_fnode->vp, RW_READER);

		/*
		 * This checks nbl_share_conflict, nbl_lock_conflict
		 */
		status = smb_nbl_conflict(dst_fnode, 0, UINT64_MAX, NBL_REMOVE);
		if (status != NT_STATUS_SUCCESS) {
			smb_node_end_crit(dst_fnode);
			smb_rename_release_src(sr);
			smb_node_release(dst_fnode);
			smb_node_release(dst_dnode);
			return (NT_STATUS_ACCESS_DENIED);
		}

		new_name = dst_fnode->od_name;
	}

	rc = smb_fsop_rename(sr, sr->user_cr,
	    src_dnode, src_fnode->od_name,
	    dst_dnode, new_name);

	if (rc == 0) {
		/*
		 * Note that renames in the same directory are normally
		 * delivered in {old,new} pairs, and clients expect them
		 * in that order, if both events are delivered.
		 */
		int a_src, a_dst; /* action codes */
		if (src_dnode == dst_dnode) {
			a_src = FILE_ACTION_RENAMED_OLD_NAME;
			a_dst = FILE_ACTION_RENAMED_NEW_NAME;
		} else {
			a_src = FILE_ACTION_REMOVED;
			a_dst = FILE_ACTION_ADDED;
		}
		smb_node_notify_change(src_dnode, a_src, src_fnode->od_name);
		smb_node_notify_change(dst_dnode, a_dst, new_name);
	}

	smb_rename_release_src(sr);

	if (dst_fqi->fq_fnode) {
		smb_node_end_crit(dst_fnode);
		smb_node_release(dst_fnode);
	}
	smb_node_release(dst_dnode);

	return (smb_rename_errno2status(rc));
}