#include <afs/param.h>
#define MAXINT (~(1<<((sizeof(int)*8)-1)))
-RCSID
- ("$Header$");
#include <errno.h>
#include <stdio.h>
#include <string.h>
+#include <stdarg.h>
#ifdef AFS_PTHREAD_ENV
#include <assert.h>
#else /* AFS_PTHREAD_ENV */
#endif /* AFS_NT40_ENV */
#include <sys/stat.h>
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
/*@printflike@*/ extern void Log(const char *format, ...);
/*@printflike@*/ extern void Abort(const char *format, ...);
struct VnodeClassInfo VnodeClassInfo[nVNODECLASSES];
-private void StickOnLruChain_r(register Vnode * vnp,
- register struct VnodeClassInfo *vcp);
+void VNLog(afs_int32 aop, afs_int32 anparms, ... );
extern int LogLevel;
static afs_int32 theLog[THELOGSIZE];
static afs_int32 vnLogPtr = 0;
void
-VNLog(afs_int32 aop, afs_int32 anparms, afs_int32 av1, afs_int32 av2,
- afs_int32 av3, afs_int32 av4)
+VNLog(afs_int32 aop, afs_int32 anparms, ... )
{
register afs_int32 temp;
- afs_int32 data[4];
+ va_list ap;
+
+ va_start(ap, anparms);
- /* copy data to array */
- data[0] = av1;
- data[1] = av2;
- data[2] = av3;
- data[3] = av4;
if (anparms > 4)
anparms = 4; /* do bounds checking */
if (vnLogPtr >= THELOGSIZE)
vnLogPtr = 0;
for (temp = 0; temp < anparms; temp++) {
- theLog[vnLogPtr++] = data[temp];
+ theLog[vnLogPtr++] = va_arg(ap, afs_int32);
if (vnLogPtr >= THELOGSIZE)
vnLogPtr = 0;
}
+ va_end(ap);
}
/* VolumeHashOffset -- returns a new value to be stored in the
if (Vn_refcount(vnp) != 0 || CheckLock(&vnp->lock))
Abort("VGetFreeVnode_r: locked vnode in lruq");
#endif
- VNLog(1, 2, Vn_id(vnp), (afs_int32) vnp, 0, 0);
+ VNLog(1, 2, Vn_id(vnp), (intptr_t)vnp, 0, 0);
/*
* it's going to be overwritten soon enough.
VnChangeState_r(vnp, VN_STATE_RELEASING);
VOL_UNLOCK;
#endif
+ /* release is, potentially, a highly latent operation due to a couple
+ * factors:
+ * - ihandle package lock contention
+ * - closing file descriptor(s) associated with ih
+ *
+ * Hance, we perform outside of the volume package lock in order to
+ * reduce the probability of contention.
+ */
IH_RELEASE(vnp->handle);
#ifdef AFS_DEMAND_ATTACH_FS
VOL_LOCK;
{
register Vnode *vnp;
VnodeId vnodeNumber;
- int bitNumber, code;
+ int bitNumber;
register struct VnodeClassInfo *vcp;
VnodeClass class;
Unique unique;
if (vnp) {
/* slot already exists. May even not be in lruq (consider store file locking a file being deleted)
* so we may have to wait for it below */
- VNLog(3, 2, vnodeNumber, (afs_int32) vnp, 0, 0);
+ VNLog(3, 2, vnodeNumber, (intptr_t)vnp, 0, 0);
VnCreateReservation_r(vnp);
if (Vn_refcount(vnp) == 1) {
}
sane:
- VNLog(4, 2, vnodeNumber, (afs_int32) vnp, 0, 0);
+ VNLog(4, 2, vnodeNumber, (intptr_t)vnp, 0, 0);
#ifndef AFS_DEMAND_ATTACH_FS
AddToVnHash(vnp);
#endif
}
- VNLog(5, 1, (afs_int32) vnp, 0, 0, 0);
+ VNLog(5, 1, (intptr_t)vnp, 0, 0, 0);
memset(&vnp->disk, 0, sizeof(vnp->disk));
vnp->changed_newTime = 0; /* set this bit when vnode is updated */
vnp->changed_oldTime = 0; /* set this on CopyOnWrite. */
{
/* vnode not cached */
Error error;
- int n, dosalv = 1;
+ int dosalv = 1;
+ ssize_t nBytes;
IHandle_t *ihP = vp->vnodeIndex[class].handle;
FdHandle_t *fdP;
Log("VnLoad: can't seek on index file vn=%u\n", Vn_id(vnp));
*ec = VIO;
goto error_encountered_nolock;
- } else if ((n = FDH_READ(fdP, (char *)&vnp->disk, vcp->diskSize))
+ } else if ((nBytes = FDH_READ(fdP, (char *)&vnp->disk, vcp->diskSize))
!= vcp->diskSize) {
/* Don't take volume off line if the inumber is out of range
* or the inode table is full. */
- if (n == BAD_IGET) {
+ if (nBytes == BAD_IGET) {
Log("VnLoad: bad inumber %s\n",
PrintInode(NULL, vp->vnodeIndex[class].handle->ih_ino));
*ec = VIO;
dosalv = 0;
- } else if (n == -1 && errno == EIO) {
+ } else if (nBytes == -1 && errno == EIO) {
/* disk error; salvage */
Log("VnLoad: Couldn't read vnode %u, volume %u (%s); volume needs salvage\n", Vn_id(vnp), V_id(vp), V_name(vp));
} else {
/* vnode is not allocated */
if (LogLevel >= 5)
Log("VnLoad: Couldn't read vnode %u, volume %u (%s); read %d bytes, errno %d\n",
- Vn_id(vnp), V_id(vp), V_name(vp), n, errno);
+ Vn_id(vnp), V_id(vp), V_name(vp), (int)nBytes, errno);
*ec = VIO;
dosalv = 0;
}
VnStore(Error * ec, Volume * vp, Vnode * vnp,
struct VnodeClassInfo * vcp, VnodeClass class)
{
- int offset, code;
+ ssize_t nBytes;
+ afs_foff_t offset;
IHandle_t *ihP = vp->vnodeIndex[class].handle;
FdHandle_t *fdP;
#ifdef AFS_DEMAND_ATTACH_FS
goto error_encountered;
}
- code = FDH_WRITE(fdP, &vnp->disk, vcp->diskSize);
- if (code != vcp->diskSize) {
+ nBytes = FDH_WRITE(fdP, &vnp->disk, vcp->diskSize);
+ if (nBytes != vcp->diskSize) {
/* Don't force volume offline if the inumber is out of
* range or the inode table is full.
*/
FDH_REALLYCLOSE(fdP);
- if (code == BAD_IGET) {
+ if (nBytes == BAD_IGET) {
Log("VnStore: bad inumber %s\n",
PrintInode(NULL,
vp->vnodeIndex[class].handle->ih_ino));
VnChangeState_r(vnp, VN_STATE_ERROR);
#endif
} else {
- Log("VnStore: Couldn't write vnode %u, volume %u (%s) (error %d)\n", Vn_id(vnp), V_id(Vn_volume(vnp)), V_name(Vn_volume(vnp)), code);
+ Log("VnStore: Couldn't write vnode %u, volume %u (%s) (error %d)\n", Vn_id(vnp), V_id(Vn_volume(vnp)), V_name(Vn_volume(vnp)), (int)nBytes);
#ifdef AFS_DEMAND_ATTACH_FS
goto error_encountered;
#else
VGetVnode_r(Error * ec, Volume * vp, VnodeId vnodeNumber, int locktype)
{ /* READ_LOCK or WRITE_LOCK, as defined in lock.h */
register Vnode *vnp;
- int code;
VnodeClass class;
struct VnodeClassInfo *vcp;
- Volume * oldvp = NULL;
*ec = 0;
if (vnp) {
/* vnode is in cache */
- VNLog(101, 2, vnodeNumber, (afs_int32) vnp, 0, 0);
+ VNLog(101, 2, vnodeNumber, (intptr_t)vnp, 0, 0);
VnCreateReservation_r(vnp);
#ifdef AFS_DEMAND_ATTACH_FS
/* Check that the vnode hasn't been removed while we were obtaining
* the lock */
- VNLog(102, 2, vnodeNumber, (afs_int32) vnp, 0, 0);
+ VNLog(102, 2, vnodeNumber, (intptr_t) vnp, 0, 0);
if ((vnp->disk.type == vNull) || (Vn_cacheCheck(vnp) == 0)) {
VnUnlock(vnp, locktype);
VnCancelReservation_r(vnp);
int writeLocked;
VnodeClass class;
struct VnodeClassInfo *vcp;
- int code;
*ec = 0;
assert(Vn_refcount(vnp) != 0);
class = vnodeIdToClass(Vn_id(vnp));
vcp = &VnodeClassInfo[class];
assert(vnp->disk.vnodeMagic == vcp->magic);
- VNLog(200, 2, Vn_id(vnp), (afs_int32) vnp, 0, 0);
+ VNLog(200, 2, Vn_id(vnp), (intptr_t) vnp, 0, 0);
#ifdef AFS_DEMAND_ATTACH_FS
writeLocked = (Vn_state(vnp) == VN_STATE_EXCLUSIVE);
PROCESS thisProcess;
LWP_CurrentProcess(&thisProcess);
#endif /* AFS_PTHREAD_ENV */
- VNLog(201, 2, (afs_int32) vnp,
+ VNLog(201, 2, (intptr_t) vnp,
((vnp->changed_newTime) << 1) | ((vnp->
changed_oldTime) << 1) | vnp->
delete, 0, 0);
/* No longer any directory entries for this vnode. Free the Vnode */
memset(&vnp->disk, 0, sizeof(vnp->disk));
/* delete flag turned off further down */
- VNLog(202, 2, Vn_id(vnp), (afs_int32) vnp, 0, 0);
+ VNLog(202, 2, Vn_id(vnp), (intptr_t) vnp, 0, 0);
} else if (vnp->changed_newTime) {
vnp->disk.serverModifyTime = now;
}
int writeLocked;
VnodeClass class;
struct VnodeClassInfo *vcp;
- int code;
#ifdef AFS_PTHREAD_ENV
pthread_t thisProcess;
#else /* AFS_PTHREAD_ENV */
class = vnodeIdToClass(Vn_id(vnp));
vcp = &VnodeClassInfo[class];
assert(vnp->disk.vnodeMagic == vcp->magic);
- VNLog(300, 2, Vn_id(vnp), (afs_int32) vnp, 0, 0);
+ VNLog(300, 2, Vn_id(vnp), (intptr_t) vnp, 0, 0);
#ifdef AFS_DEMAND_ATTACH_FS
writeLocked = (Vn_state(vnp) == VN_STATE_EXCLUSIVE);
}
- VNLog(301, 2, (afs_int32) vnp,
+ VNLog(301, 2, (intptr_t) vnp,
((vnp->changed_newTime) << 1) | ((vnp->
changed_oldTime) << 1) | vnp->
delete, 0, 0);
#endif /* AFS_PTHREAD_ENV */
if (thisProcess != vnp->writer)
Abort("VPutVnode: Vnode at 0x%x locked by another process!\n",
- (int)vnp);
+ (intptr_t)vnp);
if (vnp->delete) {
return 0;
} else {
VnStore(ec, vp, vnp, vcp, class);
}
- sane:
vcp->writes++;
vnp->changed_newTime = vnp->changed_oldTime = 0;
}
return 0;
}
+/**
+ * initial size of ihandle pointer vector.
+ *
+ * @see VInvalidateVnodesByVolume_r
+ */
+#define IH_VEC_BASE_SIZE 256
+
+/**
+ * increment amount for growing ihandle pointer vector.
+ *
+ * @see VInvalidateVnodesByVolume_r
+ */
+#define IH_VEC_INCREMENT 256
+
+/**
+ * Compile list of ihandles to be released/reallyclosed at a later time.
+ *
+ * @param[in] vp volume object pointer
+ * @param[out] vec_out vector of ihandle pointers to be released/reallyclosed
+ * @param[out] vec_len_out number of valid elements in ihandle vector
+ *
+ * @pre - VOL_LOCK is held
+ * - volume is in appropriate exclusive state (e.g. VOL_STATE_VNODE_CLOSE,
+ * VOL_STATE_VNODE_RELEASE)
+ *
+ * @post - all vnodes on VVn list are invalidated
+ * - ih_vec is populated with all valid ihandles
+ *
+ * @return operation status
+ * @retval 0 success
+ * @retval ENOMEM out of memory
+ *
+ * @todo we should handle out of memory conditions more gracefully.
+ *
+ * @internal vnode package internal use only
+ */
+static int
+VInvalidateVnodesByVolume_r(Volume * vp,
+ IHandle_t *** vec_out,
+ size_t * vec_len_out)
+{
+ int ret = 0;
+ Vnode *vnp, *nvnp;
+ size_t i = 0, vec_len;
+ IHandle_t **ih_vec, **ih_vec_new;
+
+#ifdef AFS_DEMAND_ATTACH_FS
+ VOL_UNLOCK;
+#endif /* AFS_DEMAND_ATTACH_FS */
+
+ vec_len = IH_VEC_BASE_SIZE;
+ ih_vec = malloc(sizeof(IHandle_t *) * vec_len);
+#ifdef AFS_DEMAND_ATTACH_FS
+ VOL_LOCK;
+#endif
+ if (ih_vec == NULL)
+ return ENOMEM;
+
+ /*
+ * Traverse the volume's vnode list. Pull all the ihandles out into a
+ * thread-private array for later asynchronous processing.
+ */
+#ifdef AFS_DEMAND_ATTACH_FS
+restart_traversal:
+#endif
+ for (queue_Scan(&vp->vnode_list, vnp, nvnp, Vnode)) {
+ if (vnp->handle != NULL) {
+ if (i == vec_len) {
+#ifdef AFS_DEMAND_ATTACH_FS
+ VOL_UNLOCK;
+#endif
+ vec_len += IH_VEC_INCREMENT;
+ ih_vec_new = realloc(ih_vec, sizeof(IHandle_t *) * vec_len);
+#ifdef AFS_DEMAND_ATTACH_FS
+ VOL_LOCK;
+#endif
+ if (ih_vec_new == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ ih_vec = ih_vec_new;
+#ifdef AFS_DEMAND_ATTACH_FS
+ /*
+ * Theoretically, the volume's VVn list should not change
+ * because the volume is in an exclusive state. For the
+ * sake of safety, we will restart the traversal from the
+ * the beginning (which is not expensive because we're
+ * deleting the items from the list as we go).
+ */
+ goto restart_traversal;
+#endif
+ }
+ ih_vec[i++] = vnp->handle;
+ vnp->handle = NULL;
+ }
+ DeleteFromVVnList(vnp);
+ VInvalidateVnode_r(vnp);
+ }
+
+ done:
+ *vec_out = ih_vec;
+ *vec_len_out = i;
+
+ return ret;
+}
+
/* VCloseVnodeFiles - called when a volume is going off line. All open
* files for vnodes in that volume are closed. This might be excessive,
* since we may only be taking one volume of a volume group offline.
void
VCloseVnodeFiles_r(Volume * vp)
{
- int i;
- Vnode *vnp, *nvnp;
#ifdef AFS_DEMAND_ATTACH_FS
VolState vol_state_save;
+#endif
+ IHandle_t ** ih_vec;
+ size_t i, vec_len;
+#ifdef AFS_DEMAND_ATTACH_FS
vol_state_save = VChangeState_r(vp, VOL_STATE_VNODE_CLOSE);
- VOL_UNLOCK;
#endif /* AFS_DEMAND_ATTACH_FS */
- for (queue_Scan(&vp->vnode_list, vnp, nvnp, Vnode)) {
- IH_REALLYCLOSE(vnp->handle);
- DeleteFromVVnList(vnp);
+ /* XXX need better error handling here */
+ assert(VInvalidateVnodesByVolume_r(vp,
+ &ih_vec,
+ &vec_len) == 0);
+
+ /*
+ * DAFS:
+ * now we drop VOL_LOCK while we perform some potentially very
+ * expensive operations in the background
+ */
+#ifdef AFS_DEMAND_ATTACH_FS
+ VOL_UNLOCK;
+#endif
+
+ for (i = 0; i < vec_len; i++) {
+ IH_REALLYCLOSE(ih_vec[i]);
}
+ free(ih_vec);
+
#ifdef AFS_DEMAND_ATTACH_FS
VOL_LOCK;
VChangeState_r(vp, vol_state_save);
#endif /* AFS_DEMAND_ATTACH_FS */
}
+
/**
* shut down all vnode cache state for a given volume.
*
* during this exclusive operation. This is due to the fact that we are
* generally called during the refcount 1->0 transition.
*
+ * @todo we should handle failures in VInvalidateVnodesByVolume_r more
+ * gracefully.
+ *
+ * @see VInvalidateVnodesByVolume_r
+ *
* @internal this routine is internal to the volume package
*/
void
VReleaseVnodeFiles_r(Volume * vp)
{
- int i;
- Vnode *vnp, *nvnp;
#ifdef AFS_DEMAND_ATTACH_FS
VolState vol_state_save;
+#endif
+ IHandle_t ** ih_vec;
+ size_t i, vec_len;
+#ifdef AFS_DEMAND_ATTACH_FS
vol_state_save = VChangeState_r(vp, VOL_STATE_VNODE_RELEASE);
- VOL_UNLOCK;
#endif /* AFS_DEMAND_ATTACH_FS */
- for (queue_Scan(&vp->vnode_list, vnp, nvnp, Vnode)) {
- IH_RELEASE(vnp->handle);
- DeleteFromVVnList(vnp);
+ /* XXX need better error handling here */
+ assert(VInvalidateVnodesByVolume_r(vp,
+ &ih_vec,
+ &vec_len) == 0);
+
+ /*
+ * DAFS:
+ * now we drop VOL_LOCK while we perform some potentially very
+ * expensive operations in the background
+ */
+#ifdef AFS_DEMAND_ATTACH_FS
+ VOL_UNLOCK;
+#endif
+
+ for (i = 0; i < vec_len; i++) {
+ IH_RELEASE(ih_vec[i]);
}
+ free(ih_vec);
+
#ifdef AFS_DEMAND_ATTACH_FS
VOL_LOCK;
VChangeState_r(vp, vol_state_save);