Example #1
0
/**
 * wait for all pending nodes to finish.
 *
 * @param[in] queue  work queue
 *
 * @return operation status
 *   @retval 0 success
 *
 * @post the specified queue was empty at some point; it may not be empty by
 * the time this function returns, but at some point after the function was
 * called, there were no nodes in the ready queue or blocked queue.
 */
int
afs_wq_wait_all(struct afs_work_queue *queue)
{
    int ret = 0;

    MUTEX_ENTER(&queue->lock);

    while (queue->pend_count > 0 && !queue->shutdown) {
	CV_WAIT(&queue->empty_cv, &queue->lock);
    }

    if (queue->shutdown) {
	/* queue has been shut down, but there may still be some threads
	 * running e.g. in the middle of their callback. ensure they have
	 * stopped before we return. */
	while (queue->running_count > 0) {
	    CV_WAIT(&queue->running_cv, &queue->lock);
	}
	ret = EINTR;
	goto done;
    }

 done:
    MUTEX_EXIT(&queue->lock);

    /* technically this doesn't really guarantee that the work queue is empty
     * after we return, but we do guarantee that it was empty at some point */

    return ret;
}
Example #2
0
/* Return the user's connection index of the most recently ready call; that is, a call that has received at least one reply packet */
int
multi_Select(struct multi_handle *mh)
{
    int index;
    SPLVAR;
    NETPRI;
#ifdef RX_ENABLE_LOCKS
    MUTEX_ENTER(&mh->lock);
#endif /* RX_ENABLE_LOCKS */
    while (mh->nextReady == mh->firstNotReady) {
	if (mh->nReady == mh->nConns) {
#ifdef RX_ENABLE_LOCKS
	    MUTEX_EXIT(&mh->lock);
#endif /* RX_ENABLE_LOCKS */
	    USERPRI;
	    return -1;
	}
#ifdef RX_ENABLE_LOCKS
	CV_WAIT(&mh->cv, &mh->lock);
#else /* RX_ENABLE_LOCKS */
	osi_rxSleep(mh);
#endif /* RX_ENABLE_LOCKS */
    }
    index = *(mh->nextReady);
    (mh->nextReady) += 1;
#ifdef RX_ENABLE_LOCKS
    MUTEX_EXIT(&mh->lock);
#endif /* RX_ENABLE_LOCKS */
    USERPRI;
    return index;
}
Example #3
0
afs_int32
canWrite(int fid)
{
#ifndef AFS_PTHREAD_ENV
    afs_int32 code = 0;
#endif
    extern dumpSyncP dumpSyncPtr;

    ObtainWriteLock(&dumpSyncPtr->ds_lock);

    /* let the pipe drain */
    while (dumpSyncPtr->ds_bytes > 0) {
	if (dumpSyncPtr->ds_readerStatus == DS_WAITING) {
	    dumpSyncPtr->ds_readerStatus = 0;
#ifdef AFS_PTHREAD_ENV
	    CV_BROADCAST(&dumpSyncPtr->ds_readerStatus_cond);
#else
	    code = LWP_SignalProcess(&dumpSyncPtr->ds_readerStatus);
	    if (code)
		LogError(code, "canWrite: Signal delivery failed\n");
#endif
	}
	dumpSyncPtr->ds_writerStatus = DS_WAITING;
	ReleaseWriteLock(&dumpSyncPtr->ds_lock);
#ifdef AFS_PTHREAD_ENV
	MUTEX_ENTER(&dumpSyncPtr->ds_writerStatus_mutex);
	CV_WAIT(&dumpSyncPtr->ds_writerStatus_cond, &dumpSyncPtr->ds_writerStatus_mutex);
	MUTEX_EXIT(&dumpSyncPtr->ds_writerStatus_mutex);
#else
	LWP_WaitProcess(&dumpSyncPtr->ds_writerStatus);
#endif
	ObtainWriteLock(&dumpSyncPtr->ds_lock);
    }
    return (1);
}
Example #4
0
/*
 * thread to combine salvager child logs
 * back into the main salvageserver log
 */
static void *
SalvageLogCleanupThread(void * arg)
{
    struct log_cleanup_node * cleanup;

    MUTEX_ENTER(&worker_lock);

    while (1) {
	while (queue_IsEmpty(&log_cleanup_queue)) {
	    CV_WAIT(&log_cleanup_queue.queue_change_cv, &worker_lock);
	}

	while (queue_IsNotEmpty(&log_cleanup_queue)) {
	    cleanup = queue_First(&log_cleanup_queue, log_cleanup_node);
	    queue_Remove(cleanup);
	    MUTEX_EXIT(&worker_lock);
	    SalvageLogCleanup(cleanup->pid);
	    free(cleanup);
	    MUTEX_ENTER(&worker_lock);
	}
    }

    MUTEX_EXIT(&worker_lock);
    return NULL;
}
Example #5
0
/**
 * wait for a node to complete; dequeue from done list.
 *
 * @param[in]  node     work queue node
 * @param[out] retcode  return code from work unit
 *
 * @return operation status
 *    @retval 0 sucess
 *
 * @pre ref held on node
 */
int
afs_wq_node_wait(struct afs_work_queue_node * node,
		 int * retcode)
{
    int ret = 0;

    MUTEX_ENTER(&node->lock);
    if (node->state == AFS_WQ_NODE_STATE_INIT) {
	/* not sure what to do in this case */
	goto done_sync;
    }

    while ((node->state != AFS_WQ_NODE_STATE_DONE) &&
	   (node->state != AFS_WQ_NODE_STATE_ERROR)) {
	CV_WAIT(&node->state_cv, &node->lock);
    }
    if (retcode) {
	*retcode = node->retcode;
    }

    if (node->queue == NULL) {
	/* nothing we can do */
	goto done_sync;
    }

    ret = _afs_wq_node_list_remove(node,
					AFS_WQ_NODE_STATE_INIT);

 done_sync:
    MUTEX_EXIT(&node->lock);

    return ret;
}
Example #6
0
/**
 * wait for a node's state to change from busy to something else.
 *
 * @param[in] node  node object
 *
 * @return operation status
 *    @retval 0 success
 *
 * @pre node->lock held
 *
 * @internal
 */
static int
_afs_wq_node_state_wait_busy(struct afs_work_queue_node * node)
{
    while (node->state == AFS_WQ_NODE_STATE_BUSY) {
	CV_WAIT(&node->state_cv, &node->lock);
    }

    return 0;
}
Example #7
0
void
addHPSStransaction()
{
    HPSS_LOCK;
    while (waiting) {
	waiters++;
	CV_WAIT(&auth_cond, &rxosd_hpss_mutex);
	waiters--;
    }
    HPSStransactions++;
    HPSS_UNLOCK;
}
Example #8
0
static void *
SalvageChildReaperThread(void * args)
{
    int slot, pid, status;
    struct log_cleanup_node * cleanup;

    MUTEX_ENTER(&worker_lock);

    /* loop reaping our children */
    while (1) {
	/* wait() won't block unless we have children, so
	 * block on the cond var if we're childless */
	while (current_workers == 0) {
	    CV_WAIT(&worker_cv, &worker_lock);
	}

	MUTEX_EXIT(&worker_lock);

	cleanup = (struct log_cleanup_node *) malloc(sizeof(struct log_cleanup_node));

	while (Reap_Child("salvageserver", &pid, &status) < 0) {
	    /* try to prevent livelock if something goes wrong */
	    sleep(1);
	}

	VOL_LOCK;
	for (slot = 0; slot < Parallel; slot++) {
	    if (child_slot[slot] == pid)
		break;
	}
	osi_Assert(slot < Parallel);
	child_slot[slot] = 0;
	VOL_UNLOCK;

	SALVSYNC_doneWorkByPid(pid, status);

	MUTEX_ENTER(&worker_lock);

	if (cleanup) {
	    cleanup->pid = pid;
	    queue_Append(&log_cleanup_queue, cleanup);
	    CV_SIGNAL(&log_cleanup_queue.queue_change_cv);
	}

	/* ok, we've reaped a child */
	current_workers--;
	CV_BROADCAST(&worker_cv);
    }

    return NULL;
}
Example #9
0
/**
 * shut down all threads in pool.
 *
 * @param[in] pool  thread pool object
 * @param[in] block wait for all threads to terminate, if asserted
 *
 * @return operation status
 *    @retval 0 success
 */
int
afs_tp_shutdown(struct afs_thread_pool * pool,
                int block)
{
    int ret = 0;
    struct afs_thread_pool_worker * worker, *nn;

    MUTEX_ENTER(&pool->lock);
    if (pool->state == AFS_TP_STATE_STOPPED
            || pool->state == AFS_TP_STATE_STOPPING) {
        goto done_stopped;
    }
    if (pool->state != AFS_TP_STATE_RUNNING) {
        ret = AFS_TP_ERROR;
        goto done_sync;
    }
    pool->state = AFS_TP_STATE_STOPPING;

    for (queue_Scan(&pool->thread_list, worker, nn, afs_thread_pool_worker)) {
        worker->req_shutdown = 1;
    }
    if (!pool->nthreads) {
        pool->state = AFS_TP_STATE_STOPPED;
    }
    /* need to drop lock to get a membar here */
    MUTEX_EXIT(&pool->lock);

    ret = afs_wq_shutdown(pool->work_queue);
    if (ret) {
        goto error;
    }

    MUTEX_ENTER(&pool->lock);
done_stopped:
    if (block) {
        while (pool->nthreads) {
            CV_WAIT(&pool->shutdown_cv, &pool->lock);
        }
    }
done_sync:
    MUTEX_EXIT(&pool->lock);

error:
    return ret;
}
Example #10
0
/**
 * dequeue a node from a list object.
 *
 * @param[in]    list      list object
 * @param[out]   node_out  address in which to store node object pointer
 * @param[in]    state     new node state
 * @param[in]    block     permit blocking on cv if asserted
 *
 * @return operation status
 *    @retval 0 success
 *    @retval EWOULDBLOCK block not asserted and nothing to dequeue
 *    @retval EINTR blocking wait interrupted by list shutdown
 *
 * @post node object returned with node lock held and new state set
 *
 * @internal
 */
static int
_afs_wq_node_list_dequeue(struct afs_work_queue_node_list * list,
			  struct afs_work_queue_node ** node_out,
			  afs_wq_work_state_t state,
			  int block)
{
    int ret = 0;
    struct afs_work_queue_node * node;

    MUTEX_ENTER(&list->lock);

    if (list->shutdown) {
	*node_out = NULL;
	ret = EINTR;
	goto done_sync;
    }

    if (!block && queue_IsEmpty(&list->list)) {
	*node_out = NULL;
	ret = EWOULDBLOCK;
	goto done_sync;
    }

    while (queue_IsEmpty(&list->list)) {
	if (list->shutdown) {
	    *node_out = NULL;
	    ret = EINTR;
	    goto done_sync;
	}
	CV_WAIT(&list->cv, &list->lock);
    }

    *node_out = node = queue_First(&list->list, afs_work_queue_node);

    MUTEX_ENTER(&node->lock);
    queue_Remove(node);
    node->qidx = AFS_WQ_NODE_LIST_NONE;
    _afs_wq_node_state_change(node, state);

 done_sync:
    MUTEX_EXIT(&list->lock);

    return ret;
}
Example #11
0
void
doneWriting(afs_int32 error)
{
#ifndef AFS_PTHREAD_ENV
    afs_int32 code = 0;
#endif

    /* wait for the reader */
    ObtainWriteLock(&dumpSyncPtr->ds_lock);
    while (dumpSyncPtr->ds_readerStatus != DS_WAITING) {
	LogDebug(4, "doneWriting: waiting for Reader\n");
	dumpSyncPtr->ds_writerStatus = DS_WAITING;
	ReleaseWriteLock(&dumpSyncPtr->ds_lock);
#ifdef AFS_PTHREAD_ENV
	MUTEX_ENTER(&dumpSyncPtr->ds_writerStatus_mutex);
	CV_WAIT(&dumpSyncPtr->ds_writerStatus_cond, &dumpSyncPtr->ds_writerStatus_mutex);
	MUTEX_EXIT(&dumpSyncPtr->ds_writerStatus_mutex);
#else
	LWP_WaitProcess(&dumpSyncPtr->ds_writerStatus);
#endif
	ObtainWriteLock(&dumpSyncPtr->ds_lock);
    }

    LogDebug(4, "doneWriting: setting done\n");

    /* signal that we are done */
    if (error)
	dumpSyncPtr->ds_writerStatus = DS_DONE_ERROR;
    else
	dumpSyncPtr->ds_writerStatus = DS_DONE;
    dumpSyncPtr->ds_readerStatus = 0;
#ifdef AFS_PTHREAD_ENV
    CV_BROADCAST(&dumpSyncPtr->ds_readerStatus_cond);
#else
    code = LWP_NoYieldSignal(&dumpSyncPtr->ds_readerStatus);
    if (code)
	LogError(code, "doneWriting: Signal delivery failed\n");
#endif
    ReleaseWriteLock(&dumpSyncPtr->ds_lock);
}
Example #12
0
/**
 * acquire a lock on a file on local disk.
 *
 * @param[in] dl       the VDiskLock structure corresponding to the file on disk
 * @param[in] locktype READ_LOCK if you want a read lock, or WRITE_LOCK if
 *                     you want a write lock
 * @param[in] nonblock 0 to wait for conflicting locks to clear before
 *                     obtaining the lock; 1 to fail immediately if a
 *                     conflicting lock is held by someone else
 *
 * @return operation status
 *  @retval 0 success
 *  @retval EBUSY someone else is holding a conflicting lock and nonblock=1 was
 *                specified
 *  @retval EIO   error acquiring file lock
 *
 * @note DAFS only
 *
 * @note while normal fcntl-y locks on Unix systems generally only work per-
 * process, this interface also deals with locks between threads in the
 * process in addition to different processes acquiring the lock
 */
int
VGetDiskLock(struct VDiskLock *dl, int locktype, int nonblock)
{
    int code = 0;
    osi_Assert(locktype == READ_LOCK || locktype == WRITE_LOCK);

    if (nonblock) {
	if (locktype == READ_LOCK) {
	    ObtainReadLockNoBlock(&dl->rwlock, code);
	} else {
	    ObtainWriteLockNoBlock(&dl->rwlock, code);
	}

	if (code) {
	    return EBUSY;
	}

    } else if (locktype == READ_LOCK) {
	ObtainReadLock(&dl->rwlock);
    } else {
	ObtainWriteLock(&dl->rwlock);
    }

    MUTEX_ENTER(&dl->mutex);

    if ((dl->flags & VDISKLOCK_ACQUIRING)) {
	/* Some other thread is waiting to acquire an fs lock. If nonblock=1,
	 * we can return immediately, since we know we'll need to wait to
	 * acquire. Otherwise, wait for the other thread to finish acquiring
	 * the fs lock */
	if (nonblock) {
	    code = EBUSY;
	} else {
	    while ((dl->flags & VDISKLOCK_ACQUIRING)) {
		CV_WAIT(&dl->cv, &dl->mutex);
	    }
	}
    }

    if (code == 0 && !(dl->flags & VDISKLOCK_ACQUIRED)) {
	/* no other thread holds the lock on the actual file; so grab one */

	/* first try, don't block on the lock to see if we can get it without
	 * waiting */
	code = VLockFileLock(dl->lockfile, dl->offset, locktype, 1);

	if (code == EBUSY && !nonblock) {

	    /* mark that we are waiting on the fs lock */
	    dl->flags |= VDISKLOCK_ACQUIRING;

	    MUTEX_EXIT(&dl->mutex);
	    code = VLockFileLock(dl->lockfile, dl->offset, locktype, nonblock);
	    MUTEX_ENTER(&dl->mutex);

	    dl->flags &= ~VDISKLOCK_ACQUIRING;

	    if (code == 0) {
		dl->flags |= VDISKLOCK_ACQUIRED;
	    }

	    CV_BROADCAST(&dl->cv);
	}
    }

    if (code) {
	if (locktype == READ_LOCK) {
	    ReleaseReadLock(&dl->rwlock);
	} else {
	    ReleaseWriteLock(&dl->rwlock);
	}
    } else {
	/* successfully got the lock, so inc the number of unlocks we need
	 * to do before we can unlock the actual file */
	++dl->lockers;
    }

    MUTEX_EXIT(&dl->mutex);

    return code;
}
Example #13
0
/**
 * schedule a work node for execution.
 *
 * @param[in] queue  work queue
 * @param[in] node   work node
 * @param[in] opts   options for adding, or NULL for defaults
 *
 * @return operation status
 *    @retval 0 success
 *    @retval EWOULDBLOCK queue is full and opts specified not to block
 *    @retval EINTR queue was full, we blocked to add, and the queue was
 *                  shutdown while we were blocking
 */
int
afs_wq_add(struct afs_work_queue *queue,
           struct afs_work_queue_node *node,
           struct afs_work_queue_add_opts *opts)
{
    int ret = 0;
    int donate, block, force, hithresh;
    struct afs_work_queue_node_list * list;
    struct afs_work_queue_add_opts l_opts;
    int waited_for_drain = 0;
    afs_wq_work_state_t state;

    if (!opts) {
	afs_wq_add_opts_init(&l_opts);
	opts = &l_opts;
    }

    donate = opts->donate;
    block = opts->block;
    force = opts->force;

 retry:
    MUTEX_ENTER(&node->lock);

    ret = _afs_wq_node_state_wait_busy(node);
    if (ret) {
	goto error;
    }

    if (!node->block_count && !node->error_count) {
	list = &queue->ready_list;
	state = AFS_WQ_NODE_STATE_SCHEDULED;
    } else if (node->error_count) {
	list = &queue->done_list;
	state = AFS_WQ_NODE_STATE_ERROR;
    } else {
	list = &queue->blocked_list;
	state = AFS_WQ_NODE_STATE_BLOCKED;
    }

    ret = 0;

    MUTEX_ENTER(&queue->lock);

    if (queue->shutdown) {
	ret = EINTR;
	MUTEX_EXIT(&queue->lock);
	MUTEX_EXIT(&node->lock);
	goto error;
    }

    hithresh = queue->opts.pend_hithresh;
    if (hithresh > 0 && queue->pend_count >= hithresh) {
	queue->drain = 1;
    }

    if (!force && (state == AFS_WQ_NODE_STATE_SCHEDULED
                   || state == AFS_WQ_NODE_STATE_BLOCKED)) {

	if (queue->drain) {
	    if (block) {
		MUTEX_EXIT(&node->lock);
		CV_WAIT(&queue->pend_cv, &queue->lock);

		if (queue->shutdown) {
		    ret = EINTR;
		} else {
		    MUTEX_EXIT(&queue->lock);

		    waited_for_drain = 1;

		    goto retry;
		}
	    } else {
		ret = EWOULDBLOCK;
	    }
	}
    }

    if (ret == 0) {
	queue->pend_count++;
    }
    if (waited_for_drain) {
	/* signal another thread that may have been waiting for drain */
	CV_SIGNAL(&queue->pend_cv);
    }

    MUTEX_EXIT(&queue->lock);

    if (ret) {
	goto error;
    }

    if (!donate)
	node->refcount++;
    node->queue = queue;

    ret = _afs_wq_node_list_enqueue(list,
					 node,
					 state);
 error:
    return ret;
}
Example #14
0
/* rxi_ReadProc -- internal version.
 *
 * LOCKS USED -- called at netpri
 */
int
rxi_ReadProc(struct rx_call *call, char *buf,
	     int nbytes)
{
    struct rx_packet *cp = call->currentPacket;
    struct rx_packet *rp;
    int requestCount;
    unsigned int t;

/* XXXX took out clock_NewTime from here.  Was it needed? */
    requestCount = nbytes;

    /* Free any packets from the last call to ReadvProc/WritevProc */
    if (queue_IsNotEmpty(&call->iovq)) {
#ifdef RXDEBUG_PACKET
        call->iovqc -=
#endif /* RXDEBUG_PACKET */
            rxi_FreePackets(0, &call->iovq);
    }

    do {
	if (call->nLeft == 0) {
	    /* Get next packet */
	    MUTEX_ENTER(&call->lock);
	    for (;;) {
		if (call->error || (call->mode != RX_MODE_RECEIVING)) {
		    if (call->error) {
                        call->mode = RX_MODE_ERROR;
			MUTEX_EXIT(&call->lock);
			return 0;
		    }
		    if (call->mode == RX_MODE_SENDING) {
                        MUTEX_EXIT(&call->lock);
			rxi_FlushWrite(call);
                        MUTEX_ENTER(&call->lock);
			continue;
		    }
		}
		if (queue_IsNotEmpty(&call->rq)) {
		    /* Check that next packet available is next in sequence */
		    rp = queue_First(&call->rq, rx_packet);
		    if (rp->header.seq == call->rnext) {
			afs_int32 error;
			struct rx_connection *conn = call->conn;
			queue_Remove(rp);
#ifdef RX_TRACK_PACKETS
			rp->flags &= ~RX_PKTFLAG_RQ;
#endif
#ifdef RXDEBUG_PACKET
                        call->rqc--;
#endif /* RXDEBUG_PACKET */

			/* RXS_CheckPacket called to undo RXS_PreparePacket's
			 * work.  It may reduce the length of the packet by up
			 * to conn->maxTrailerSize, to reflect the length of the
			 * data + the header. */
			if ((error =
			     RXS_CheckPacket(conn->securityObject, call,
					     rp))) {
			    /* Used to merely shut down the call, but now we
			     * shut down the whole connection since this may
			     * indicate an attempt to hijack it */

			    MUTEX_EXIT(&call->lock);
			    rxi_ConnectionError(conn, error);
			    MUTEX_ENTER(&conn->conn_data_lock);
			    rp = rxi_SendConnectionAbort(conn, rp, 0, 0);
			    MUTEX_EXIT(&conn->conn_data_lock);
			    rxi_FreePacket(rp);

			    return 0;
			}
			call->rnext++;
			cp = call->currentPacket = rp;
#ifdef RX_TRACK_PACKETS
			call->currentPacket->flags |= RX_PKTFLAG_CP;
#endif
			call->curvec = 1;	/* 0th vec is always header */
			/* begin at the beginning [ more or less ], continue
			 * on until the end, then stop. */
			call->curpos =
			    (char *)cp->wirevec[1].iov_base +
			    call->conn->securityHeaderSize;
			call->curlen =
			    cp->wirevec[1].iov_len -
			    call->conn->securityHeaderSize;

			/* Notice that this code works correctly if the data
			 * size is 0 (which it may be--no reply arguments from
			 * server, for example).  This relies heavily on the
			 * fact that the code below immediately frees the packet
			 * (no yields, etc.).  If it didn't, this would be a
			 * problem because a value of zero for call->nLeft
			 * normally means that there is no read packet */
			call->nLeft = cp->length;
			hadd32(call->bytesRcvd, cp->length);

			/* Send a hard ack for every rxi_HardAckRate+1 packets
			 * consumed. Otherwise schedule an event to send
			 * the hard ack later on.
			 */
			call->nHardAcks++;
			if (!(call->flags & RX_CALL_RECEIVE_DONE)) {
			    if (call->nHardAcks > (u_short) rxi_HardAckRate) {
				rxevent_Cancel(call->delayedAckEvent, call,
					       RX_CALL_REFCOUNT_DELAY);
				rxi_SendAck(call, 0, 0, RX_ACK_DELAY, 0);
			    } else {
				struct clock when, now;
				clock_GetTime(&now);
				when = now;
				/* Delay to consolidate ack packets */
				clock_Add(&when, &rx_hardAckDelay);
				if (!call->delayedAckEvent
				    || clock_Gt(&call->delayedAckEvent->
						eventTime, &when)) {
				    rxevent_Cancel(call->delayedAckEvent,
						   call,
						   RX_CALL_REFCOUNT_DELAY);
                                    MUTEX_ENTER(&rx_refcnt_mutex);
				    CALL_HOLD(call, RX_CALL_REFCOUNT_DELAY);
                                    MUTEX_EXIT(&rx_refcnt_mutex);
                                    call->delayedAckEvent =
				      rxevent_PostNow(&when, &now,
						     rxi_SendDelayedAck, call,
						     0);
				}
			    }
			}
			break;
		    }
		}

                /*
                 * If we reach this point either we have no packets in the
                 * receive queue or the next packet in the queue is not the
                 * one we are looking for.  There is nothing else for us to
                 * do but wait for another packet to arrive.
                 */

		/* Are there ever going to be any more packets? */
		if (call->flags & RX_CALL_RECEIVE_DONE) {
		    MUTEX_EXIT(&call->lock);
		    return requestCount - nbytes;
		}
		/* Wait for in-sequence packet */
		call->flags |= RX_CALL_READER_WAIT;
		clock_NewTime();
		call->startWait = clock_Sec();
		while (call->flags & RX_CALL_READER_WAIT) {
#ifdef	RX_ENABLE_LOCKS
		    CV_WAIT(&call->cv_rq, &call->lock);
#else
		    osi_rxSleep(&call->rq);
#endif
		}
                cp = call->currentPacket;

		call->startWait = 0;
#ifdef RX_ENABLE_LOCKS
		if (call->error) {
		    MUTEX_EXIT(&call->lock);
		    return 0;
		}
#endif /* RX_ENABLE_LOCKS */
	    }
	    MUTEX_EXIT(&call->lock);
	} else
	    /* osi_Assert(cp); */
	    /* MTUXXX  this should be replaced by some error-recovery code before shipping */
	    /* yes, the following block is allowed to be the ELSE clause (or not) */
	    /* It's possible for call->nLeft to be smaller than any particular
	     * iov_len.  Usually, recvmsg doesn't change the iov_len, since it
	     * reflects the size of the buffer.  We have to keep track of the
	     * number of bytes read in the length field of the packet struct.  On
	     * the final portion of a received packet, it's almost certain that
	     * call->nLeft will be smaller than the final buffer. */
	    while (nbytes && cp) {
		t = MIN((int)call->curlen, nbytes);
		t = MIN(t, (int)call->nLeft);
		memcpy(buf, call->curpos, t);
		buf += t;
		nbytes -= t;
		call->curpos += t;
		call->curlen -= t;
		call->nLeft -= t;

		if (!call->nLeft) {
		    /* out of packet.  Get another one. */
#ifdef RX_TRACK_PACKETS
		    call->currentPacket->flags &= ~RX_PKTFLAG_CP;
#endif
		    rxi_FreePacket(cp);
		    cp = call->currentPacket = (struct rx_packet *)0;
		} else if (!call->curlen) {
		    /* need to get another struct iov */
		    if (++call->curvec >= cp->niovecs) {
			/* current packet is exhausted, get ready for another */
			/* don't worry about curvec and stuff, they get set somewhere else */
#ifdef RX_TRACK_PACKETS
			call->currentPacket->flags &= ~RX_PKTFLAG_CP;
#endif
			rxi_FreePacket(cp);
			cp = call->currentPacket = (struct rx_packet *)0;
			call->nLeft = 0;
		    } else {
			call->curpos =
			    (char *)cp->wirevec[call->curvec].iov_base;
			call->curlen = cp->wirevec[call->curvec].iov_len;
		    }
		}
	    }
	if (!nbytes) {
	    /* user buffer is full, return */
	    return requestCount;
	}

    } while (nbytes);

    return requestCount;
}
Example #15
0
static void
SalvageServer(int argc, char **argv)
{
    int pid, ret;
    struct SalvageQueueNode * node;
    pthread_t tid;
    pthread_attr_t attrs;
    int slot;
    VolumePackageOptions opts;

    /* All entries to the log will be appended.  Useful if there are
     * multiple salvagers appending to the log.
     */

    CheckLogFile((char *)AFSDIR_SERVER_SALSRVLOG_FILEPATH);
#ifndef AFS_NT40_ENV
#ifdef AFS_LINUX20_ENV
    fcntl(fileno(logFile), F_SETFL, O_APPEND);	/* Isn't this redundant? */
#else
    fcntl(fileno(logFile), F_SETFL, FAPPEND);	/* Isn't this redundant? */
#endif
#endif
    setlinebuf(logFile);

    fprintf(logFile, "%s\n", cml_version_number);
    LogCommandLine(argc, argv, "Online Salvage Server",
		   SalvageVersion, "Starting OpenAFS", Log);
    /* Get and hold a lock for the duration of the salvage to make sure
     * that no other salvage runs at the same time.  The routine
     * VInitVolumePackage2 (called below) makes sure that a file server or
     * other volume utilities don't interfere with the salvage.
     */

    /* even demand attach online salvager
     * still needs this because we don't want
     * a stand-alone salvager to conflict with
     * the salvager daemon */
    ObtainSharedSalvageLock();

    child_slot = (int *) malloc(Parallel * sizeof(int));
    osi_Assert(child_slot != NULL);
    memset(child_slot, 0, Parallel * sizeof(int));

    /* initialize things */
    VOptDefaults(salvageServer, &opts);
    if (VInitVolumePackage2(salvageServer, &opts)) {
	Log("Shutting down: errors encountered initializing volume package\n");
	Exit(1);
    }
    DInit(10);
    queue_Init(&pending_q);
    queue_Init(&log_cleanup_queue);
    MUTEX_INIT(&worker_lock, "worker", MUTEX_DEFAULT, 0);
    CV_INIT(&worker_cv, "worker", CV_DEFAULT, 0);
    CV_INIT(&log_cleanup_queue.queue_change_cv, "queuechange", CV_DEFAULT, 0);
    osi_Assert(pthread_attr_init(&attrs) == 0);

    /* start up the reaper and log cleaner threads */
    osi_Assert(pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED) == 0);
    osi_Assert(pthread_create(&tid,
			  &attrs,
			  &SalvageChildReaperThread,
			  NULL) == 0);
    osi_Assert(pthread_create(&tid,
			  &attrs,
			  &SalvageLogCleanupThread,
			  NULL) == 0);
    osi_Assert(pthread_create(&tid,
			  &attrs,
			  &SalvageLogScanningThread,
			  NULL) == 0);

    /* loop forever serving requests */
    while (1) {
	node = SALVSYNC_getWork();
	osi_Assert(node != NULL);

	Log("dispatching child to salvage volume %u...\n",
	    node->command.sop.parent);

	VOL_LOCK;
	/* find a slot */
	for (slot = 0; slot < Parallel; slot++) {
	  if (!child_slot[slot])
	    break;
	}
	osi_Assert (slot < Parallel);

    do_fork:
	pid = Fork();
	if (pid == 0) {
	    VOL_UNLOCK;
	    ret = DoSalvageVolume(node, slot);
	    Exit(ret);
	} else if (pid < 0) {
	    Log("failed to fork child worker process\n");
	    sleep(1);
	    goto do_fork;
	} else {
	    child_slot[slot] = pid;
	    node->pid = pid;
	    VOL_UNLOCK;

	    MUTEX_ENTER(&worker_lock);
	    current_workers++;

	    /* let the reaper thread know another worker was spawned */
	    CV_BROADCAST(&worker_cv);

	    /* if we're overquota, wait for the reaper */
	    while (current_workers >= Parallel) {
		CV_WAIT(&worker_cv, &worker_lock);
	    }
	    MUTEX_EXIT(&worker_lock);
	}
    }
}
Example #16
0
int
rxi_WriteProc(struct rx_call *call, char *buf,
	      int nbytes)
{
    struct rx_connection *conn = call->conn;
    unsigned int t;
    int requestCount = nbytes;

    /* Free any packets from the last call to ReadvProc/WritevProc */
    if (!opr_queue_IsEmpty(&call->app.iovq)) {
#ifdef RXDEBUG_PACKET
        call->iovqc -=
#endif /* RXDEBUG_PACKET */
            rxi_FreePackets(0, &call->app.iovq);
    }

    if (call->app.mode != RX_MODE_SENDING) {
	if ((conn->type == RX_SERVER_CONNECTION)
	    && (call->app.mode == RX_MODE_RECEIVING)) {
	    call->app.mode = RX_MODE_SENDING;
	    if (call->app.currentPacket) {
#ifdef RX_TRACK_PACKETS
		call->app.currentPacket->flags &= ~RX_PKTFLAG_CP;
#endif
		rxi_FreePacket(call->app.currentPacket);
		call->app.currentPacket = NULL;
		call->app.nLeft = 0;
		call->app.nFree = 0;
	    }
	} else {
	    return 0;
	}
    }

    /* Loop condition is checked at end, so that a write of 0 bytes
     * will force a packet to be created--specially for the case where
     * there are 0 bytes on the stream, but we must send a packet
     * anyway. */
    do {
	if (call->app.nFree == 0) {
	    MUTEX_ENTER(&call->lock);
            if (call->error)
                call->app.mode = RX_MODE_ERROR;
	    if (!call->error && call->app.currentPacket) {
		clock_NewTime();	/* Bogus:  need new time package */
		/* The 0, below, specifies that it is not the last packet:
		 * there will be others. PrepareSendPacket may
		 * alter the packet length by up to
		 * conn->securityMaxTrailerSize */
		call->app.bytesSent += call->app.currentPacket->length;
		rxi_PrepareSendPacket(call, call->app.currentPacket, 0);
                /* PrepareSendPacket drops the call lock */
                rxi_WaitforTQBusy(call);
#ifdef RX_TRACK_PACKETS
		call->app.currentPacket->flags |= RX_PKTFLAG_TQ;
#endif
		opr_queue_Append(&call->tq,
				 &call->app.currentPacket->entry);
#ifdef RXDEBUG_PACKET
                call->tqc++;
#endif /* RXDEBUG_PACKET */
#ifdef RX_TRACK_PACKETS
                call->app.currentPacket->flags &= ~RX_PKTFLAG_CP;
#endif
                call->app.currentPacket = NULL;

		/* If the call is in recovery, let it exhaust its current
		 * retransmit queue before forcing it to send new packets
		 */
		if (!(call->flags & (RX_CALL_FAST_RECOVER))) {
		    rxi_Start(call, 0);
		}
	    } else if (call->app.currentPacket) {
#ifdef RX_TRACK_PACKETS
		call->app.currentPacket->flags &= ~RX_PKTFLAG_CP;
#endif
		rxi_FreePacket(call->app.currentPacket);
		call->app.currentPacket = NULL;
	    }
	    /* Wait for transmit window to open up */
	    while (!call->error
		   && call->tnext + 1 > call->tfirst + (2 * call->twind)) {
		clock_NewTime();
		call->startWait = clock_Sec();

#ifdef	RX_ENABLE_LOCKS
		CV_WAIT(&call->cv_twind, &call->lock);
#else
		call->flags |= RX_CALL_WAIT_WINDOW_ALLOC;
		osi_rxSleep(&call->twind);
#endif

		call->startWait = 0;
#ifdef RX_ENABLE_LOCKS
		if (call->error) {
                    call->app.mode = RX_MODE_ERROR;
		    MUTEX_EXIT(&call->lock);
		    return 0;
		}
#endif /* RX_ENABLE_LOCKS */
	    }
	    if ((call->app.currentPacket = rxi_AllocSendPacket(call, nbytes))) {
#ifdef RX_TRACK_PACKETS
		call->app.currentPacket->flags |= RX_PKTFLAG_CP;
#endif
		call->app.nFree = call->app.currentPacket->length;
		call->app.curvec = 1;	/* 0th vec is always header */
		/* begin at the beginning [ more or less ], continue
		 * on until the end, then stop. */
		call->app.curpos =
		    (char *) call->app.currentPacket->wirevec[1].iov_base +
		    call->conn->securityHeaderSize;
		call->app.curlen =
		    call->app.currentPacket->wirevec[1].iov_len -
		    call->conn->securityHeaderSize;
	    }
	    if (call->error) {
                call->app.mode = RX_MODE_ERROR;
		if (call->app.currentPacket) {
#ifdef RX_TRACK_PACKETS
		    call->app.currentPacket->flags &= ~RX_PKTFLAG_CP;
#endif
		    rxi_FreePacket(call->app.currentPacket);
		    call->app.currentPacket = NULL;
		}
		MUTEX_EXIT(&call->lock);
		return 0;
	    }
	    MUTEX_EXIT(&call->lock);
	}

	if (call->app.currentPacket && (int)call->app.nFree < nbytes) {
	    /* Try to extend the current buffer */
	    int len, mud;
	    len = call->app.currentPacket->length;
	    mud = rx_MaxUserDataSize(call);
	    if (mud > len) {
		int want;
		want = MIN(nbytes - (int)call->app.nFree, mud - len);
		rxi_AllocDataBuf(call->app.currentPacket, want,
				 RX_PACKET_CLASS_SEND_CBUF);
		if (call->app.currentPacket->length > (unsigned)mud)
		    call->app.currentPacket->length = mud;
		call->app.nFree += (call->app.currentPacket->length - len);
	    }
	}

	/* If the remaining bytes fit in the buffer, then store them
	 * and return.  Don't ship a buffer that's full immediately to
	 * the peer--we don't know if it's the last buffer yet */

	if (!call->app.currentPacket) {
	    call->app.nFree = 0;
	}

	while (nbytes && call->app.nFree) {

	    t = MIN((int)call->app.curlen, nbytes);
	    t = MIN((int)call->app.nFree, t);
	    memcpy(call->app.curpos, buf, t);
	    buf += t;
	    nbytes -= t;
	    call->app.curpos += t;
	    call->app.curlen -= (u_short)t;
	    call->app.nFree -= (u_short)t;

	    if (!call->app.curlen) {
		/* need to get another struct iov */
		if (++call->app.curvec >= call->app.currentPacket->niovecs) {
		    /* current packet is full, extend or send it */
		    call->app.nFree = 0;
		} else {
		    call->app.curpos =
			call->app.currentPacket->wirevec[call->app.curvec].iov_base;
		    call->app.curlen =
			call->app.currentPacket->wirevec[call->app.curvec].iov_len;
		}
	    }
	}			/* while bytes to send and room to send them */

	/* might be out of space now */
	if (!nbytes) {
	    return requestCount;
	} else;			/* more data to send, so get another packet and keep going */
    } while (nbytes);

    return requestCount - nbytes;
}
Example #17
0
/* rxi_ReadvProc -- internal version.
 *
 * Fills in an iovec with pointers to the packet buffers. All packets
 * except the last packet (new current packet) are moved to the iovq
 * while the application is processing the data.
 *
 * LOCKS USED -- called at netpri.
 */
int
rxi_ReadvProc(struct rx_call *call, struct iovec *iov, int *nio, int maxio,
	      int nbytes)
{
    int bytes;

    /* Free any packets from the last call to ReadvProc/WritevProc */
    if (!opr_queue_IsEmpty(&call->app.iovq)) {
#ifdef RXDEBUG_PACKET
        call->iovqc -=
#endif /* RXDEBUG_PACKET */
            rxi_FreePackets(0, &call->app.iovq);
    }

    if (call->app.mode == RX_MODE_SENDING) {
	rxi_FlushWrite(call);
    }

    MUTEX_ENTER(&call->lock);
    if (call->error)
        goto error;

    /* Get whatever data is currently available in the receive queue.
     * If rxi_FillReadVec sends an ack packet then it is possible
     * that we will receive more data while we drop the call lock
     * to send the packet. Set the RX_CALL_IOVEC_WAIT flag
     * here to avoid a race with the receive thread if we send
     * hard acks in rxi_FillReadVec. */
    call->flags |= RX_CALL_IOVEC_WAIT;
    call->iovNBytes = nbytes;
    call->iovMax = maxio;
    call->iovNext = 0;
    call->iov = iov;
    rxi_FillReadVec(call, 0);

    /* if we need more data then sleep until the receive thread has
     * filled in the rest. */
    if (!call->error && call->iovNBytes && call->iovNext < call->iovMax
	&& !(call->flags & RX_CALL_RECEIVE_DONE)) {
	call->flags |= RX_CALL_READER_WAIT;
	clock_NewTime();
	call->startWait = clock_Sec();
	while (call->flags & RX_CALL_READER_WAIT) {
#ifdef	RX_ENABLE_LOCKS
	    CV_WAIT(&call->cv_rq, &call->lock);
#else
	    osi_rxSleep(&call->rq);
#endif
	}
	call->startWait = 0;
    }
    call->flags &= ~RX_CALL_IOVEC_WAIT;

    if (call->error)
        goto error;

    call->iov = NULL;
    *nio = call->iovNext;
    bytes = nbytes - call->iovNBytes;
    MUTEX_EXIT(&call->lock);
    return bytes;

  error:
    MUTEX_EXIT(&call->lock);
    call->app.mode = RX_MODE_ERROR;
    return 0;
}
Example #18
0
/* rxi_ReadProc -- internal version.
 *
 * LOCKS USED -- called at netpri
 */
int
rxi_ReadProc(struct rx_call *call, char *buf,
	     int nbytes)
{
    int requestCount;
    int code;
    unsigned int t;

/* XXXX took out clock_NewTime from here.  Was it needed? */
    requestCount = nbytes;

    /* Free any packets from the last call to ReadvProc/WritevProc */
    if (!opr_queue_IsEmpty(&call->app.iovq)) {
#ifdef RXDEBUG_PACKET
        call->iovqc -=
#endif /* RXDEBUG_PACKET */
            rxi_FreePackets(0, &call->app.iovq);
    }

    do {
	if (call->app.nLeft == 0) {
	    /* Get next packet */
	    MUTEX_ENTER(&call->lock);
	    for (;;) {
		if (call->error || (call->app.mode != RX_MODE_RECEIVING)) {
		    if (call->error) {
                        call->app.mode = RX_MODE_ERROR;
			MUTEX_EXIT(&call->lock);
			return 0;
		    }
		    if (call->app.mode == RX_MODE_SENDING) {
                        MUTEX_EXIT(&call->lock);
			rxi_FlushWrite(call);
                        MUTEX_ENTER(&call->lock);
			continue;
		    }
		}

		code = rxi_GetNextPacket(call);
		if (code)
		     return 0;

		if (call->app.currentPacket) {
		    if (!(call->flags & RX_CALL_RECEIVE_DONE)) {
			if (call->nHardAcks > (u_short) rxi_HardAckRate) {
			    rxi_CancelDelayedAckEvent(call);
			    rxi_SendAck(call, 0, 0, RX_ACK_DELAY, 0);
			} else {
			    /* Delay to consolidate ack packets */
			    rxi_PostDelayedAckEvent(call, &rx_hardAckDelay);
			}
		    }
		    break;
		}

                /*
                 * If we reach this point either we have no packets in the
                 * receive queue or the next packet in the queue is not the
                 * one we are looking for.  There is nothing else for us to
                 * do but wait for another packet to arrive.
                 */

		/* Are there ever going to be any more packets? */
		if (call->flags & RX_CALL_RECEIVE_DONE) {
		    MUTEX_EXIT(&call->lock);
		    return requestCount - nbytes;
		}
		/* Wait for in-sequence packet */
		call->flags |= RX_CALL_READER_WAIT;
		clock_NewTime();
		call->startWait = clock_Sec();
		while (call->flags & RX_CALL_READER_WAIT) {
#ifdef	RX_ENABLE_LOCKS
		    CV_WAIT(&call->cv_rq, &call->lock);
#else
		    osi_rxSleep(&call->rq);
#endif
		}

		call->startWait = 0;
#ifdef RX_ENABLE_LOCKS
		if (call->error) {
		    MUTEX_EXIT(&call->lock);
		    return 0;
		}
#endif /* RX_ENABLE_LOCKS */
	    }
	    MUTEX_EXIT(&call->lock);
	} else
	    /* osi_Assert(cp); */
	    /* MTUXXX  this should be replaced by some error-recovery code before shipping */
	    /* yes, the following block is allowed to be the ELSE clause (or not) */
	    /* It's possible for call->app.nLeft to be smaller than any particular
	     * iov_len.  Usually, recvmsg doesn't change the iov_len, since it
	     * reflects the size of the buffer.  We have to keep track of the
	     * number of bytes read in the length field of the packet struct.  On
	     * the final portion of a received packet, it's almost certain that
	     * call->app.nLeft will be smaller than the final buffer. */
	    while (nbytes && call->app.currentPacket) {
		t = MIN((int)call->app.curlen, nbytes);
		t = MIN(t, (int)call->app.nLeft);
		memcpy(buf, call->app.curpos, t);
		buf += t;
		nbytes -= t;
		call->app.curpos += t;
		call->app.curlen -= t;
		call->app.nLeft -= t;

		if (!call->app.nLeft) {
		    /* out of packet.  Get another one. */
#ifdef RX_TRACK_PACKETS
		    call->app.currentPacket->flags &= ~RX_PKTFLAG_CP;
#endif
		    rxi_FreePacket(call->app.currentPacket);
		    call->app.currentPacket = NULL;
		} else if (!call->app.curlen) {
		    /* need to get another struct iov */
		    if (++call->app.curvec >= call->app.currentPacket->niovecs) {
			/* current packet is exhausted, get ready for another */
			/* don't worry about curvec and stuff, they get set somewhere else */
#ifdef RX_TRACK_PACKETS
			call->app.currentPacket->flags &= ~RX_PKTFLAG_CP;
#endif
			rxi_FreePacket(call->app.currentPacket);
			call->app.currentPacket = NULL;
			call->app.nLeft = 0;
		    } else {
			call->app.curpos =
			    call->app.currentPacket->wirevec[call->app.curvec].iov_base;
			call->app.curlen =
			    call->app.currentPacket->wirevec[call->app.curvec].iov_len;
		    }
		}
	    }
	if (!nbytes) {
	    /* user buffer is full, return */
	    return requestCount;
	}

    } while (nbytes);

    return requestCount;
}
Example #19
0
static int
readHPSSconf()
{
    int i, j, cos, code = ENOENT;
    afs_uint64 value;
    struct stat64 tstat;
    char tbuffer[256];
    char minstr[128];
    char maxstr[128];
    char tmpstr[128];
    static time_t lastVersion = 0;

    if (!initialized) {
	MUTEX_INIT(&rxosd_hpss_mutex, "rxosd hpss lock", 0, 0);
	memset(&info, 0, sizeof(info));
	initialized = 1;
    }
    sprintf(tbuffer, "%s/HPSS.conf", AFSDIR_SERVER_BIN_DIRPATH);
    if (stat64(tbuffer, &tstat) == 0) {
	code = 0;
#ifdef AFS_AIX53_ENV
	if (tstat.st_mtime > lastVersion) {
#else
	if (tstat.st_mtim.tv_sec > lastVersion) {
#endif
	    bufio_p bp = BufioOpen(tbuffer, O_RDONLY, 0);
	    if (bp) {
		while (1) {
		    j = BufioGets(bp, tbuffer, sizeof(tbuffer));
		    if (j < 0)
			break;
		    j = sscanf(tbuffer, "COS %u min %s max %s",
				 &cos, &minstr, &maxstr);
		    if (j == 3) {
		        for (i=0; i<MAXCOS; i++) {
			    if (cos == info[i].cosId)
			        break;
			    if (info[i].cosId == 0)
			        break;
		        }
		        if (i<MAXCOS) 
			    code = fillInfo(&info[i], cos, minstr, maxstr);
		    } else {
		        j = sscanf(tbuffer, "PRINCIPAL %s", &tmpstr);
			if (j == 1) {
			    strncpy(ourPrincipal, tmpstr, sizeof(ourPrincipal));
			    ourPrincipal[sizeof(ourPrincipal) -1] = 0; /*just in case */
			    continue;
			}
		        j = sscanf(tbuffer, "KEYTAB %s", &tmpstr);
			if (j == 1) {
			    strncpy(ourKeytab, tmpstr, sizeof(ourKeytab));
			    ourKeytab[sizeof(ourKeytab) -1] = 0; /*just in case */
			    continue;
			}
		        j = sscanf(tbuffer, "PATH %s", &tmpstr);
			if (j == 1) {
			    strncpy(ourPath, tmpstr, sizeof(ourPath));
			    ourPath[sizeof(ourPath) -1] = 0; /*just in case */
			    continue;
			}
		        j = sscanf(tbuffer, "LIB %s", &tmpstr);
			if (j == 1) {
			    int k;
			    for (k=0; k<MAX_HPSS_LIBS; k++) {
				if (parms.ourLibs[k] == NULL)
				    break;
				if (strcmp(parms.ourLibs[k], tmpstr) == 0)
				    goto found;
			    }
			    for (k=0; k<MAX_HPSS_LIBS; k++) { 
				if (parms.ourLibs[k] == NULL) {
				    parms.ourLibs[k] = malloc(strlen(tmpstr) + 1);
				    sprintf(parms.ourLibs[k], "%s", tmpstr);
				    break;
				}
			    }
			found:
			    continue;
			}
		    }
		}
		BufioClose(bp);
	    }
	    if (!code)
#ifdef AFS_AIX53_ENV
		lastVersion = tstat.st_mtime;
#else
		lastVersion = tstat.st_mtim.tv_sec;
#endif
	}
    }
    return code;
}

static void checkCode(afs_int32 code)
{
    /*
     * If we get a code of -13 back from HPSS something is wrong with our
     * authentication. Try to force e new authentication.
     */
    if (code == -13) 	/* permission */
	*(rxosd_var->lastAuth) = 0;
}

/* 
 * This routine is called by the FiveMinuteCcheck
 */
afs_int32 
authenticate_for_hpss(void)
{
    afs_int32 code = 0, i;
    time_t now = time(0);
    static int authenticated = 0;
    char *principal;
    char *keytab;

    code = readHPSSconf();
    if (code)
	return code;

    if (now - *(rxosd_var->lastAuth) > TWENTYDAYS) {
	if (authenticated) {
	    waiting = 1;
	    while (HPSStransactions > 0) {
	        CV_WAIT(&auth_cond, &rxosd_hpss_mutex);
	    }
	    hpss_ClientAPIReset();
	    hpss_PurgeLoginCred();
	    authenticated = 0;
	}
	principal = &ourPrincipal;
	keytab = &ourKeytab;
        code = hpss_SetLoginCred(principal, hpss_authn_mech_krb5,
                             hpss_rpc_cred_client,
                             hpss_rpc_auth_type_keytab, keytab);
        if (!code) {
	    authenticated = 1;
	    *(rxosd_var->lastAuth) = now;
	}
	waiting = 0;
        if (waiters)
	    assert(pthread_cond_broadcast(&auth_cond) == 0);
    }
    return code;
}
Example #20
0
/* rxi_WritevProc -- internal version.
 *
 * Send buffers allocated in rxi_WritevAlloc.
 *
 * LOCKS USED -- called at netpri.
 */
int
rxi_WritevProc(struct rx_call *call, struct iovec *iov, int nio, int nbytes)
{
    struct rx_packet *cp = NULL;
#ifdef RX_TRACK_PACKETS
    struct rx_packet *p, *np;
#endif
    int nextio;
    int requestCount;
    struct rx_queue tmpq;
#ifdef RXDEBUG_PACKET
    u_short tmpqc;
#endif

    requestCount = nbytes;
    nextio = 0;

    MUTEX_ENTER(&call->lock);
    if (call->error) {
        call->mode = RX_MODE_ERROR;
    } else if (call->mode != RX_MODE_SENDING) {
	call->error = RX_PROTOCOL_ERROR;
    }
#ifdef AFS_GLOBAL_RXLOCK_KERNEL
    rxi_WaitforTQBusy(call);
#endif /* AFS_GLOBAL_RXLOCK_KERNEL */
    cp = call->currentPacket;

    if (call->error) {
        call->mode = RX_MODE_ERROR;
	MUTEX_EXIT(&call->lock);
	if (cp) {
#ifdef RX_TRACK_PACKETS
            cp->flags &= ~RX_PKTFLAG_CP;
            cp->flags |= RX_PKTFLAG_IOVQ;
#endif
	    queue_Prepend(&call->iovq, cp);
#ifdef RXDEBUG_PACKET
            call->iovqc++;
#endif /* RXDEBUG_PACKET */
	    call->currentPacket = (struct rx_packet *)0;
	}
#ifdef RXDEBUG_PACKET
        call->iovqc -=
#endif /* RXDEBUG_PACKET */
            rxi_FreePackets(0, &call->iovq);
	return 0;
    }

    /* Loop through the I/O vector adjusting packet pointers.
     * Place full packets back onto the iovq once they are ready
     * to send. Set RX_PROTOCOL_ERROR if any problems are found in
     * the iovec. We put the loop condition at the end to ensure that
     * a zero length write will push a short packet. */
    nextio = 0;
    queue_Init(&tmpq);
#ifdef RXDEBUG_PACKET
    tmpqc = 0;
#endif /* RXDEBUG_PACKET */
    do {
	if (call->nFree == 0 && cp) {
	    clock_NewTime();	/* Bogus:  need new time package */
	    /* The 0, below, specifies that it is not the last packet:
	     * there will be others. PrepareSendPacket may
	     * alter the packet length by up to
	     * conn->securityMaxTrailerSize */
	    hadd32(call->bytesSent, cp->length);
	    rxi_PrepareSendPacket(call, cp, 0);
	    queue_Append(&tmpq, cp);
#ifdef RXDEBUG_PACKET
            tmpqc++;
#endif /* RXDEBUG_PACKET */
            cp = call->currentPacket = (struct rx_packet *)0;

	    /* The head of the iovq is now the current packet */
	    if (nbytes) {
		if (queue_IsEmpty(&call->iovq)) {
                    MUTEX_EXIT(&call->lock);
		    call->error = RX_PROTOCOL_ERROR;
#ifdef RXDEBUG_PACKET
                    tmpqc -=
#endif /* RXDEBUG_PACKET */
                        rxi_FreePackets(0, &tmpq);
		    return 0;
		}
		cp = queue_First(&call->iovq, rx_packet);
		queue_Remove(cp);
#ifdef RX_TRACK_PACKETS
                cp->flags &= ~RX_PKTFLAG_IOVQ;
#endif
#ifdef RXDEBUG_PACKET
                call->iovqc--;
#endif /* RXDEBUG_PACKET */
#ifdef RX_TRACK_PACKETS
                cp->flags |= RX_PKTFLAG_CP;
#endif
		call->currentPacket = cp;
		call->nFree = cp->length;
		call->curvec = 1;
		call->curpos =
		    (char *)cp->wirevec[1].iov_base +
		    call->conn->securityHeaderSize;
		call->curlen =
		    cp->wirevec[1].iov_len - call->conn->securityHeaderSize;
	    }
	}

	if (nbytes) {
	    /* The next iovec should point to the current position */
	    if (iov[nextio].iov_base != call->curpos
		|| iov[nextio].iov_len > (int)call->curlen) {
		call->error = RX_PROTOCOL_ERROR;
                MUTEX_EXIT(&call->lock);
		if (cp) {
#ifdef RX_TRACK_PACKETS
		    cp->flags &= ~RX_PKTFLAG_CP;
#endif
                    queue_Prepend(&tmpq, cp);
#ifdef RXDEBUG_PACKET
                    tmpqc++;
#endif /* RXDEBUG_PACKET */
                    cp = call->currentPacket = (struct rx_packet *)0;
		}
#ifdef RXDEBUG_PACKET
                tmpqc -=
#endif /* RXDEBUG_PACKET */
                    rxi_FreePackets(0, &tmpq);
		return 0;
	    }
	    nbytes -= iov[nextio].iov_len;
	    call->curpos += iov[nextio].iov_len;
	    call->curlen -= iov[nextio].iov_len;
	    call->nFree -= iov[nextio].iov_len;
	    nextio++;
	    if (call->curlen == 0) {
		if (++call->curvec > cp->niovecs) {
		    call->nFree = 0;
		} else {
		    call->curpos = (char *)cp->wirevec[call->curvec].iov_base;
		    call->curlen = cp->wirevec[call->curvec].iov_len;
		}
	    }
	}
    } while (nbytes && nextio < nio);

    /* Move the packets from the temporary queue onto the transmit queue.
     * We may end up with more than call->twind packets on the queue. */

#ifdef RX_TRACK_PACKETS
    for (queue_Scan(&tmpq, p, np, rx_packet))
    {
        p->flags |= RX_PKTFLAG_TQ;
    }
#endif

    if (call->error)
        call->mode = RX_MODE_ERROR;

    queue_SpliceAppend(&call->tq, &tmpq);

    if (!(call->flags & (RX_CALL_FAST_RECOVER | RX_CALL_FAST_RECOVER_WAIT))) {
	rxi_Start(0, call, 0, 0);
    }

    /* Wait for the length of the transmit queue to fall below call->twind */
    while (!call->error && call->tnext + 1 > call->tfirst + (2 * call->twind)) {
	clock_NewTime();
	call->startWait = clock_Sec();
#ifdef	RX_ENABLE_LOCKS
	CV_WAIT(&call->cv_twind, &call->lock);
#else
	call->flags |= RX_CALL_WAIT_WINDOW_ALLOC;
	osi_rxSleep(&call->twind);
#endif
	call->startWait = 0;
    }

    /* cp is no longer valid since we may have given up the lock */
    cp = call->currentPacket;

    if (call->error) {
        call->mode = RX_MODE_ERROR;
        call->currentPacket = NULL;
        MUTEX_EXIT(&call->lock);
	if (cp) {
#ifdef RX_TRACK_PACKETS
	    cp->flags &= ~RX_PKTFLAG_CP;
#endif
	    rxi_FreePacket(cp);
	}
	return 0;
    }
    MUTEX_EXIT(&call->lock);

    return requestCount - nbytes;
}