Пример #1
0
/* Free a buffered I/O handle */
int
stream_close(StreamHandle_t * streamP, int reallyClose)
{
    ssize_t rc;
    int retval = 0;

    osi_Assert(streamP != NULL);
    if (streamP->str_direction == STREAM_DIRECTION_WRITE
	&& streamP->str_bufoff > 0) {
	rc = OS_PWRITE(streamP->str_fd, streamP->str_buffer,
		      streamP->str_bufoff, streamP->str_fdoff);
	if (rc < 0) {
	    retval = -1;
	} else {
	    streamP->str_fdoff += rc;
	}
    }
    if (reallyClose) {
	rc = OS_CLOSE(streamP->str_fd);
	if (rc < 0) {
	    retval = -1;
	}
    }
    streamP->str_fd = INVALID_FD;

    IH_LOCK;
    DLL_INSERT_TAIL(streamP, streamAvailHead, streamAvailTail,
		    str_next, str_prev);
    IH_UNLOCK;
    return retval;
}
Пример #2
0
/*
 * Actually close the file descriptor handle and return it to
 * the free list.
 */
int
fd_reallyclose(FdHandle_t * fdP)
{
    FD_t closeFd;
    IHandle_t *ihP;

    if (!fdP)
	return 0;

    IH_LOCK;
    osi_Assert(ih_Inited);
    osi_Assert(fdInUseCount > 0);
    osi_Assert(fdP->fd_status == FD_HANDLE_INUSE ||
               fdP->fd_status == FD_HANDLE_CLOSING);

    ihP = fdP->fd_ih;
    closeFd = fdP->fd_fd;
    fdP->fd_refcnt--;

    if (fdP->fd_refcnt == 0) {
	DLL_DELETE(fdP, ihP->ih_fdhead, ihP->ih_fdtail, fd_ihnext, fd_ihprev);
	DLL_INSERT_TAIL(fdP, fdAvailHead, fdAvailTail, fd_next, fd_prev);

	fdP->fd_status = FD_HANDLE_AVAIL;
	fdP->fd_refcnt = 0;
	fdP->fd_ih = NULL;
	fdP->fd_fd = INVALID_FD;
    }

    /* All the file descriptor handles have been closed; reset
     * the IH_REALLY_CLOSED flag indicating that ih_reallyclose
     * has completed its job.
     */
    if (!ihP->ih_fdhead) {
	ihP->ih_flags &= ~IH_REALLY_CLOSED;
    }

    if (fdP->fd_refcnt == 0) {
	IH_UNLOCK;
	OS_CLOSE(closeFd);
	IH_LOCK;
	fdInUseCount -= 1;
    }

    /* If this is not the only reference to the Inode then we can decrement
     * the reference count, otherwise we need to call ih_release. */
    if (ihP->ih_refcnt > 1)
	ihP->ih_refcnt--;
    else
	_ih_release_r(ihP);

    IH_UNLOCK;

    return 0;
}
Пример #3
0
/* Close all unused file descriptors associated with the inode
 * handle. Called with IH_LOCK held. May drop and reacquire
 * IH_LOCK. Sets the IH_REALLY_CLOSED flag in the inode handle
 * if it fails to close all file handles.
 */
static int
ih_fdclose(IHandle_t * ihP)
{
    int closeCount, closedAll;
    FdHandle_t *fdP, *head, *tail, *next;

    osi_Assert(ihP->ih_refcnt > 0);

    closedAll = 1;
    DLL_INIT_LIST(head, tail);
    ihP->ih_flags &= ~IH_REALLY_CLOSED;

    /*
     * Remove the file descriptors for this Inode from the LRU queue
     * and the IHandle queue and put them on a temporary queue so we
     * can drop the lock before we close the files.
     */
    for (fdP = ihP->ih_fdhead; fdP != NULL; fdP = next) {
	next = fdP->fd_ihnext;
	osi_Assert(fdP->fd_ih == ihP);
	osi_Assert(fdP->fd_status == FD_HANDLE_OPEN
	       || fdP->fd_status == FD_HANDLE_INUSE
	       || fdP->fd_status == FD_HANDLE_CLOSING);
	if (fdP->fd_status == FD_HANDLE_OPEN) {
	    /* Note that FdHandle_t's do not count against the parent
	     * IHandle_t ref count when they are FD_HANDLE_OPEN. So, we don't
	     * need to dec the parent IHandle_t ref count for each one we pull
	     * off here. */
	    DLL_DELETE(fdP, ihP->ih_fdhead, ihP->ih_fdtail, fd_ihnext,
		       fd_ihprev);
	    DLL_DELETE(fdP, fdLruHead, fdLruTail, fd_next, fd_prev);
	    DLL_INSERT_TAIL(fdP, head, tail, fd_next, fd_prev);
	} else {
	    closedAll = 0;
	    fdP->fd_status = FD_HANDLE_CLOSING;
	    ihP->ih_flags |= IH_REALLY_CLOSED;
	}
    }

    /* If the ihandle reference count is 1, we should have
     * closed all file descriptors.
     */
    if (ihP->ih_refcnt == 1 || closedAll) {
	osi_Assert(closedAll);
	osi_Assert(!ihP->ih_fdhead);
	osi_Assert(!ihP->ih_fdtail);
    }

    if (head == NULL) {
	return 0;		/* No file descriptors closed */
    }

    IH_UNLOCK;
    /*
     * Close the file descriptors
     */
    closeCount = 0;
    for (fdP = head; fdP != NULL; fdP = fdP->fd_next) {
	OS_CLOSE(fdP->fd_fd);
	fdP->fd_status = FD_HANDLE_AVAIL;
	fdP->fd_refcnt = 0;
	fdP->fd_fd = INVALID_FD;
	fdP->fd_ih = NULL;
	closeCount++;
    }

    IH_LOCK;
    osi_Assert(fdInUseCount >= closeCount);
    fdInUseCount -= closeCount;

    /*
     * Append the temporary queue to the list of available descriptors
     */
    if (fdAvailHead == NULL) {
	fdAvailHead = head;
	fdAvailTail = tail;
    } else {
	fdAvailTail->fd_next = head;
	head->fd_prev = fdAvailTail;
	fdAvailTail = tail;
    }

    return 0;
}
Пример #4
0
/*
 * Get a file descriptor handle given an Inode handle
 */
FdHandle_t *
ih_open(IHandle_t * ihP)
{
    FdHandle_t *fdP;
    FD_t fd;
    FD_t closeFd;

    if (!ihP)			/* XXX should log here in the fileserver */
	return NULL;

    IH_LOCK;

    /* Do we already have an open file handle for this Inode? */
    for (fdP = ihP->ih_fdtail; fdP != NULL; fdP = fdP->fd_ihprev) {
	if (fdP->fd_status == FD_HANDLE_CLOSING) {
	    /* The handle was open when an IH_REALLYCLOSE was issued, so we
	     * cannot reuse it; it will be closed soon. */
	    continue;
	}
#ifndef HAVE_PIO
	/*
	 * If we don't have positional i/o, don't try to share fds, since
	 * we can't do so in a threadsafe way.
	 */
	if (fdP->fd_status == FD_HANDLE_INUSE) {
	    continue;
	}
	osi_Assert(fdP->fd_status == FD_HANDLE_OPEN);
#else /* HAVE_PIO */
	osi_Assert(fdP->fd_status != FD_HANDLE_AVAIL);
#endif /* HAVE_PIO */

	fdP->fd_refcnt++;
	if (fdP->fd_status == FD_HANDLE_OPEN) {
	    fdP->fd_status = FD_HANDLE_INUSE;
	    DLL_DELETE(fdP, fdLruHead, fdLruTail, fd_next, fd_prev);
	}
	ihP->ih_refcnt++;
	IH_UNLOCK;
	return fdP;
    }

    /*
     * Try to open the Inode, return NULL on error.
     */
    fdInUseCount += 1;
    IH_UNLOCK;
ih_open_retry:
    fd = OS_IOPEN(ihP);
    IH_LOCK;
    if (fd == INVALID_FD && (errno != EMFILE || fdLruHead == NULL) ) {
	fdInUseCount -= 1;
	IH_UNLOCK;
	return NULL;
    }

    /* fdCacheSize limits the size of the descriptor cache, but
     * we permit the number of open files to exceed fdCacheSize.
     * We only recycle open file descriptors when the number
     * of open files reaches the size of the cache */
    if ((fdInUseCount > fdCacheSize || fd == INVALID_FD)  && fdLruHead != NULL) {
	fdP = fdLruHead;
	osi_Assert(fdP->fd_status == FD_HANDLE_OPEN);
	DLL_DELETE(fdP, fdLruHead, fdLruTail, fd_next, fd_prev);
	DLL_DELETE(fdP, fdP->fd_ih->ih_fdhead, fdP->fd_ih->ih_fdtail,
		   fd_ihnext, fd_ihprev);
	closeFd = fdP->fd_fd;
	if (fd == INVALID_FD) {
	    fdCacheSize--;          /* reduce in order to not run into here too often */
	    DLL_INSERT_TAIL(fdP, fdAvailHead, fdAvailTail, fd_next, fd_prev);
	    fdP->fd_status = FD_HANDLE_AVAIL;
	    fdP->fd_ih = NULL;
	    fdP->fd_fd = INVALID_FD;
	    IH_UNLOCK;
	    OS_CLOSE(closeFd);
	    goto ih_open_retry;
	}
    } else {
	if (fdAvailHead == NULL) {
	    fdHandleAllocateChunk();
	}
	fdP = fdAvailHead;
	osi_Assert(fdP->fd_status == FD_HANDLE_AVAIL);
	DLL_DELETE(fdP, fdAvailHead, fdAvailTail, fd_next, fd_prev);
	closeFd = INVALID_FD;
    }

    fdP->fd_status = FD_HANDLE_INUSE;
    fdP->fd_fd = fd;
    fdP->fd_ih = ihP;
    fdP->fd_refcnt++;

    ihP->ih_refcnt++;

    /* Add this handle to the Inode's list of open descriptors */
    DLL_INSERT_TAIL(fdP, ihP->ih_fdhead, ihP->ih_fdtail, fd_ihnext,
		    fd_ihprev);

    if (closeFd != INVALID_FD) {
	IH_UNLOCK;
	OS_CLOSE(closeFd);
	IH_LOCK;
	fdInUseCount -= 1;
    }

    IH_UNLOCK;
    return fdP;
}
Пример #5
0
/**
 * handle a single vol header as part of VWalkVolumeHeaders.
 *
 * @param[in] dp      disk partition
 * @param[in] volfunc function to call when a vol header is successfully read
 * @param[in] name    full path name to the .vol header
 * @param[out] hdr    header data read in from the .vol header
 * @param[in] locked  1 if the partition headers are locked, 0 otherwise
 * @param[in] rock    the rock to pass to volfunc
 *
 * @return operation status
 *  @retval 0  success
 *  @retval -1 fatal error, stop scanning
 *  @retval 1  failed to read header
 *  @retval 2  volfunc callback indicated error after header read
 */
static int
_VHandleVolumeHeader(struct DiskPartition64 *dp, VWalkVolFunc volfunc,
                     const char *name, struct VolumeDiskHeader *hdr,
                     int locked, void *rock)
{
    int error = 0;
    FD_t fd;

    if ((fd = OS_OPEN(name, O_RDONLY, 0)) == INVALID_FD
        || OS_READ(fd, hdr, sizeof(*hdr))
        != sizeof(*hdr)
        || hdr->stamp.magic != VOLUMEHEADERMAGIC) {
        error = 1;
    }

    if (fd != INVALID_FD) {
	OS_CLOSE(fd);
    }

#ifdef AFSFS_DEMAND_ATTACH_FS
    if (locked) {
	VPartHeaderUnlock(dp);
    }
#endif /* AFS_DEMAND_ATTACH_FS */

    if (!error && volfunc) {
	/* the volume header seems fine; call the caller-supplied
	 * 'we-found-a-volume-header' function */
	int last = 1;

#ifdef AFS_DEMAND_ATTACH_FS
	if (!locked) {
	    last = 0;
	}
#endif /* AFS_DEMAND_ATTACH_FS */

	error = (*volfunc) (dp, name, hdr, last, rock);
	if (error < 0) {
	    return -1;
	}
	if (error) {
	    error = 2;
	}
    }

#ifdef AFS_DEMAND_ATTACH_FS
    if (error && !locked) {
	int code;
	/* retry reading the volume header under the partition
	 * header lock, just to be safe and ensure we're not
	 * racing something rewriting the vol header */
	code = VPartHeaderLock(dp, WRITE_LOCK);
	if (code) {
	    Log("Error acquiring partition write lock when "
		"looking at header %s\n", name);
	    return -1;
	}

	return _VHandleVolumeHeader(dp, volfunc, name, hdr, 1, rock);
    }
#endif /* AFS_DEMAND_ATTACH_FS */

    return error;
}
Пример #6
0
/*
 * Get a file descriptor handle given an Inode handle
 */
FdHandle_t *
ih_open(IHandle_t * ihP)
{
    FdHandle_t *fdP;
    FD_t fd;
    FD_t closeFd;

    if (!ihP)			/* XXX should log here in the fileserver */
	return NULL;

    IH_LOCK;

    /* Do we already have an open file handle for this Inode? */
    for (fdP = ihP->ih_fdtail; fdP != NULL; fdP = fdP->fd_ihprev) {
	if (fdP->fd_status != FD_HANDLE_INUSE) {
	    assert(fdP->fd_status == FD_HANDLE_OPEN);
	    fdP->fd_status = FD_HANDLE_INUSE;
	    DLL_DELETE(fdP, fdLruHead, fdLruTail, fd_next, fd_prev);
	    ihP->ih_refcnt++;
	    IH_UNLOCK;
	    (void)FDH_SEEK(fdP, 0, SEEK_SET);
	    return fdP;
	}
    }

    /*
     * Try to open the Inode, return NULL on error.
     */
    fdInUseCount += 1;
    IH_UNLOCK;
ih_open_retry:
    fd = OS_IOPEN(ihP);
    IH_LOCK;
    if (fd == INVALID_FD && (errno != EMFILE || fdLruHead == NULL) ) {
	fdInUseCount -= 1;
	IH_UNLOCK;
	return NULL;
    }

    /* fdCacheSize limits the size of the descriptor cache, but
     * we permit the number of open files to exceed fdCacheSize.
     * We only recycle open file descriptors when the number
     * of open files reaches the size of the cache */
    if ((fdInUseCount > fdCacheSize || fd == INVALID_FD)  && fdLruHead != NULL) {
	fdP = fdLruHead;
	assert(fdP->fd_status == FD_HANDLE_OPEN);
	DLL_DELETE(fdP, fdLruHead, fdLruTail, fd_next, fd_prev);
	DLL_DELETE(fdP, fdP->fd_ih->ih_fdhead, fdP->fd_ih->ih_fdtail,
		   fd_ihnext, fd_ihprev);
	closeFd = fdP->fd_fd;
	if (fd == INVALID_FD) {
	    fdCacheSize--;          /* reduce in order to not run into here too often */
	    DLL_INSERT_TAIL(fdP, fdAvailHead, fdAvailTail, fd_next, fd_prev);
	    fdP->fd_status = FD_HANDLE_AVAIL;
	    fdP->fd_ih = NULL;
	    fdP->fd_fd = INVALID_FD;
	    IH_UNLOCK;
	    OS_CLOSE(closeFd);
	    goto ih_open_retry;
	}
    } else {
	if (fdAvailHead == NULL) {
	    fdHandleAllocateChunk();
	}
	fdP = fdAvailHead;
	assert(fdP->fd_status == FD_HANDLE_AVAIL);
	DLL_DELETE(fdP, fdAvailHead, fdAvailTail, fd_next, fd_prev);
	closeFd = INVALID_FD;
    }

    fdP->fd_status = FD_HANDLE_INUSE;
    fdP->fd_fd = fd;
    fdP->fd_ih = ihP;

    ihP->ih_refcnt++;

    /* Add this handle to the Inode's list of open descriptors */
    DLL_INSERT_TAIL(fdP, ihP->ih_fdhead, ihP->ih_fdtail, fd_ihnext,
		    fd_ihprev);

    if (closeFd != INVALID_FD) {
	IH_UNLOCK;
	OS_CLOSE(closeFd);
	IH_LOCK;
	fdInUseCount -= 1;
    }

    IH_UNLOCK;
    return fdP;
}