#include <afsconfig.h>
#include "afs/param.h"
-
-RCSID("$Header$");
-
+
+
#include "afs/sysincludes.h"
#include "afsincludes.h"
#include "afs/afs_stats.h" /* statistics */
#include "afs/lock.h"
#include "afs/afs_cbqueue.h"
-#ifdef AFS_DISCON_ENV
-
#define dv_match(vc, fstat) \
- ((vc->m.DataVersion.low == fstat.DataVersion) && \
- (vc->m.DataVersion.high == fstat.dataVersionHigh))
+ ((vc->f.m.DataVersion.low == fstat.DataVersion) && \
+ (vc->f.m.DataVersion.high == fstat.dataVersionHigh))
-/*! Global list of dirty vcaches. */
-/*! Last added element. */
-struct vcache *afs_DDirtyVCList = NULL;
-/*! Head of list. */
-struct vcache *afs_DDirtyVCListStart = NULL;
-/*! Previous element in the list. */
-struct vcache *afs_DDirtyVCListPrev = NULL;
+/*! Circular queue of dirty vcaches */
+struct afs_q afs_disconDirty;
-/*! Locks list of dirty vcaches. */
-afs_rwlock_t afs_DDirtyVCListLock;
+/*! Circular queue of vcaches with shadow directories */
+struct afs_q afs_disconShadow;
+
+/*! Locks both of these lists. Must be write locked for anything other than
+ * list traversal */
+afs_rwlock_t afs_disconDirtyLock;
extern afs_int32 *afs_dvhashTbl; /*Data cache hash table */
extern afs_int32 *afs_dchashTbl; /*Data cache hash table */
extern afs_int32 *afs_dcnextTbl; /*Dcache hash table links */
extern struct dcache **afs_indexTable; /*Pointers to dcache entries */
-/*! Vnode number. On file creation, use the current
- * value and increment it.
+/*! Vnode number. On file creation, use the current value and increment it.
*/
afs_uint32 afs_DisconVnode = 2;
afs_int32 afs_ConflictPolicy = SERVER_WINS;
+static void afs_DisconDiscardAllShadows(int, afs_ucred_t *);
+void afs_DbgListDirEntries(struct VenusFid *afid);
+
+
/*!
* Find the first dcache of a file that has the specified fid.
* Similar to afs_FindDCache, only that it takes a fid instead
*
* \return The found dcache or NULL.
*/
-struct dcache *afs_FindDCacheByFid(register struct VenusFid *afid)
+struct dcache *
+afs_FindDCacheByFid(struct VenusFid *afid)
{
- register afs_int32 i, index;
- register struct dcache *tdc = NULL;
+ afs_int32 i, index;
+ struct dcache *tdc = NULL;
i = DVHash(afid);
ObtainWriteLock(&afs_xdcache, 758);
for (index = afs_dvhashTbl[i]; index != NULLIDX;) {
if (afs_indexUnique[index] == afid->Fid.Unique) {
- tdc = afs_GetDSlot(index, NULL);
- ReleaseReadLock(&tdc->tlock);
- if (!FidCmp(&tdc->f.fid, afid)) {
- break; /* leaving refCount high for caller */
+ tdc = afs_GetValidDSlot(index);
+ if (tdc) {
+ ReleaseReadLock(&tdc->tlock);
+ if (!FidCmp(&tdc->f.fid, afid)) {
+ break; /* leaving refCount high for caller */
+ }
+ afs_PutDCache(tdc);
}
- afs_PutDCache(tdc);
}
index = afs_dvnextTbl[index];
}
*
* \return Mask of operations.
*/
-int afs_GenStoreStatus(struct vcache *avc, struct AFSStoreStatus *astat)
+int
+afs_GenStoreStatus(struct vcache *avc, struct AFSStoreStatus *astat)
{
- if (!avc || !astat || !avc->ddirty_flags)
+ if (!avc || !astat || !avc->f.ddirty_flags)
return 0;
/* Clean up store stat. */
memset(astat, 0, sizeof(struct AFSStoreStatus));
- if (avc->ddirty_flags & VDisconSetTime) {
+ if (avc->f.ddirty_flags & VDisconSetTime) {
/* Update timestamp. */
- astat->ClientModTime = avc->m.Date;
+ astat->ClientModTime = avc->f.m.Date;
astat->Mask |= AFS_SETMODTIME;
}
- if (avc->ddirty_flags & VDisconSetMode) {
+ if (avc->f.ddirty_flags & VDisconSetMode) {
/* Copy the mode bits. */
- astat->UnixModeBits = avc->m.Mode;
+ astat->UnixModeBits = avc->f.m.Mode;
astat->Mask |= AFS_SETMODE;
}
*
* \param hdata The fid to be filled.
*/
-int get_parent_dir_fid_hook(void *hdata,
- char *aname,
- afs_int32 vnode,
- afs_int32 unique)
+static int
+get_parent_dir_fid_hook(void *hdata, char *aname, afs_int32 vnode,
+ afs_int32 unique)
{
struct VenusFid *tfid = (struct VenusFid *) hdata;
*
* \param avc The file's vhash entry.
* \param afid Put the fid here.
+ *
+ * \return 0 on success, -1 on failure
*/
-int afs_GetParentDirFid(struct vcache *avc, struct VenusFid *afid)
+int
+afs_GetParentDirFid(struct vcache *avc, struct VenusFid *afid)
{
struct dcache *tdc;
- afid->Cell = avc->fid.Cell;
- afid->Fid.Volume = avc->fid.Fid.Volume;
+ afid->Cell = avc->f.fid.Cell;
+ afid->Fid.Volume = avc->f.fid.Fid.Volume;
- if (vType(avc) == VREG) {
+ switch (vType(avc)) {
+ case VREG:
+ case VLNK:
/* Normal files have the dir fid embedded in the vcache. */
- afid->Fid.Vnode = avc->parentVnode;
- afid->Fid.Unique = avc->parentUnique;
-
- } else if (vType(avc) == VDIR) {
+ afid->Fid.Vnode = avc->f.parent.vnode;
+ afid->Fid.Unique = avc->f.parent.unique;
+ break;
+ case VDIR:
/* If dir or parent dir created locally*/
- tdc = afs_FindDCacheByFid(&avc->fid);
+ tdc = afs_FindDCacheByFid(&avc->f.fid);
if (tdc) {
+ afid->Fid.Unique = 0;
/* Lookup each entry for the fid. It should be the first. */
afs_dir_EnumerateDir(tdc, &get_parent_dir_fid_hook, afid);
afs_PutDCache(tdc);
+ if (afid->Fid.Unique == 0) {
+ return -1;
+ }
+ } else {
+ return -1;
}
+ break;
+ default:
+ return -1;
}
return 0;
* \param hdata NameAndFid structure containin a pointer to a fid
* and an allocate name. The name will be filled when hit.
*/
-int get_vnode_name_hook(void *hdata,
- char *aname,
- afs_int32 vnode,
- afs_int32 unique)
+static int
+get_vnode_name_hook(void *hdata, char *aname, afs_int32 vnode,
+ afs_int32 unique)
{
struct NameAndFid *nf = (struct NameAndFid *) hdata;
* \param deleted Has this file been deleted? If yes, use the shadow
* dir for looking up the name.
*/
-int afs_GetVnodeName(struct vcache *avc,
- struct VenusFid *afid,
- char *aname,
- int deleted)
+int
+afs_GetVnodeName(struct vcache *avc, struct VenusFid *afid, char *aname,
+ int deleted)
{
int code = 0;
struct dcache *tdc;
/* For deleted files, get the shadow dir's tdc: */
/* Get the parent dir's vcache that contains the shadow fid. */
- parent_fid.Cell = avc->fid.Cell;
- parent_fid.Fid.Volume = avc->fid.Fid.Volume;
- if (avc->ddirty_flags & VDisconRename) {
+ parent_fid.Cell = avc->f.fid.Cell;
+ parent_fid.Fid.Volume = avc->f.fid.Fid.Volume;
+ if (avc->f.ddirty_flags & VDisconRename) {
/* For renames the old dir fid is needed. */
- parent_fid.Fid.Vnode = avc->oldVnode;
- parent_fid.Fid.Unique = avc->oldUnique;
+ parent_fid.Fid.Vnode = avc->f.oldParent.vnode;
+ parent_fid.Fid.Unique = avc->f.oldParent.unique;
} else {
parent_fid.Fid.Vnode = afid->Fid.Vnode;
parent_fid.Fid.Unique = afid->Fid.Unique;
parent_vc = afs_FindVCache(&parent_fid, 0, 1);
ReleaseSharedLock(&afs_xvcache);
if (!parent_vc) {
- return ENOENT;
+ return ENETDOWN;
}
- shadow_fid.Cell = parent_vc->fid.Cell;
- shadow_fid.Fid.Volume = parent_vc->fid.Fid.Volume;
- shadow_fid.Fid.Vnode = parent_vc->shVnode;
- shadow_fid.Fid.Unique = parent_vc->shUnique;
+ shadow_fid.Cell = parent_vc->f.fid.Cell;
+ shadow_fid.Fid.Volume = parent_vc->f.fid.Fid.Volume;
+ shadow_fid.Fid.Vnode = parent_vc->f.shadow.vnode;
+ shadow_fid.Fid.Unique = parent_vc->f.shadow.unique;
afs_PutVCache(parent_vc);
} /* if (deleted) */
if (tdc) {
- tnf.fid = &avc->fid;
- tnf.name_len = 0;
+ tnf.fid = &avc->f.fid;
+ tnf.name_len = -1;
tnf.name = aname;
afs_dir_EnumerateDir(tdc, &get_vnode_name_hook, &tnf);
afs_PutDCache(tdc);
+ if (tnf.name_len == -1)
+ code = ENOENT;
} else {
- code = ENOENT;
+ /* printf("Directory dcache not found!\n"); */
+ code = ENETDOWN;
}
return code;
/*!
* Lookup dirty deleted vnodes in this dir.
*/
-int chk_del_children_hook(void *hdata,
- char *aname,
- afs_int32 vnode,
- afs_int32 unique)
+static int
+chk_del_children_hook(void *hdata, char *aname, afs_int32 vnode,
+ afs_int32 unique)
{
struct VenusFid tfid;
struct DirtyChildrenCount *v = (struct DirtyChildrenCount *) hdata;
return 0;
/* Get this file's vcache. */
- tfid.Cell = v->vc->fid.Cell;
- tfid.Fid.Volume = v->vc->fid.Fid.Volume;
+ tfid.Cell = v->vc->f.fid.Cell;
+ tfid.Fid.Volume = v->vc->f.fid.Fid.Volume;
tfid.Fid.Vnode = vnode;
tfid.Fid.Unique = unique;
tvc = afs_FindVCache(&tfid, 0, 1);
ReleaseSharedLock(&afs_xvcache);
- /* Count unfinished dirty children. VDisconShadowed can still be set,
- * because we need it to remove the shadow dir.
- */
+ /* Count unfinished dirty children. */
if (tvc) {
- if (tvc->ddirty_flags)
+ ObtainReadLock(&tvc->lock);
+ if (tvc->f.ddirty_flags)
v->count++;
+ ReleaseReadLock(&tvc->lock);
afs_PutVCache(tvc);
}
*
* \note afs_DDirtyVCListLock must be write locked.
*/
-int afs_CheckDeletedChildren(struct vcache *avc)
+int
+afs_CheckDeletedChildren(struct vcache *avc)
{
struct dcache *tdc;
struct DirtyChildrenCount dcc;
struct VenusFid shadow_fid;
- if (!(avc->ddirty_flags & VDisconShadowed))
+ if (!avc->f.shadow.vnode)
/* Empty dir. */
return 0;
- shadow_fid.Cell = avc->fid.Cell;
- shadow_fid.Fid.Volume = avc->fid.Fid.Volume;
- shadow_fid.Fid.Vnode = avc->shVnode;
- shadow_fid.Fid.Unique = avc->shUnique;
+ shadow_fid.Cell = avc->f.fid.Cell;
+ shadow_fid.Fid.Volume = avc->f.fid.Fid.Volume;
+ shadow_fid.Fid.Vnode = avc->f.shadow.vnode;
+ shadow_fid.Fid.Unique = avc->f.shadow.unique;
dcc.count = 0;
/*!
* Changes a file's parent fid references.
*/
-int fix_children_fids_hook(void *hdata,
- char *aname,
- afs_int32 vnode,
- afs_int32 unique)
+static int
+fix_children_fids_hook(void *hdata, char *aname, afs_int32 vnode,
+ afs_int32 unique)
{
struct VenusFid tfid;
struct VenusFid *afid = (struct VenusFid *) hdata;
/* Change the fields. */
if (tvc) {
- tvc->parentVnode = afid->Fid.Vnode;
- tvc->parentUnique = afid->Fid.Unique;
+ tvc->f.parent.vnode = afid->Fid.Vnode;
+ tvc->f.parent.unique = afid->Fid.Unique;
afs_PutVCache(tvc);
}
* \param old_fid The current dir's fid.
* \param new_fid The new dir's fid.
*/
-void afs_FixChildrenFids(struct VenusFid *old_fid, struct VenusFid *new_fid)
+void
+afs_FixChildrenFids(struct VenusFid *old_fid, struct VenusFid *new_fid)
{
struct dcache *tdc;
}
}
-int list_dir_hook(void *hdata, char *aname, afs_int32 vnode, afs_int32 unique)
+static int
+list_dir_hook(void *hdata, char *aname, afs_int32 vnode, afs_int32 unique)
{
- printf("list_dir_hook: %s v:%u u:%u\n", aname, vnode, unique);
+ /* printf("list_dir_hook: %s v:%u u:%u\n", aname, vnode, unique); */
return 0;
}
-void afs_DbgListDirEntries(struct VenusFid *afid)
+void
+afs_DbgListDirEntries(struct VenusFid *afid)
{
struct dcache *tdc;
}
/*!
+ * Find the parent vcache for a given child
+ *
+ * \param avc The vcache whose parent is required
+ * \param afid Fid structure in which parent's fid should be stored
+ * \param aname An AFSNAMEMAX sized buffer to hold the parents name
+ * \param adp A pointer to a struct vcache* which will be set to the
+ * parent vcache
+ *
+ * \return An error code. 0 indicates success, EAGAIN that the vnode should
+ * be deferred to later in the resync process
+ */
+
+int
+afs_GetParentVCache(struct vcache *avc, int deleted, struct VenusFid *afid,
+ char *aname, struct vcache **adp)
+{
+ int code;
+
+ *adp = NULL;
+
+ if (afs_GetParentDirFid(avc, afid)) {
+ /* printf("afs_GetParentVCache: Couldn't find parent dir's FID.\n"); */
+ return ENETDOWN;
+ }
+
+ code = afs_GetVnodeName(avc, afid, aname, deleted);
+ if (code) {
+ /* printf("afs_GetParentVCache: Couldn't find file name\n"); */
+ goto end;
+ }
+
+ ObtainSharedLock(&afs_xvcache, 766);
+ *adp = afs_FindVCache(afid, 0, 1);
+ ReleaseSharedLock(&afs_xvcache);
+ if (!*adp) {
+ /* printf("afs_GetParentVCache: Couldn't find parent dir's vcache\n"); */
+ code = ENETDOWN;
+ goto end;
+ }
+
+ if ((*adp)->f.ddirty_flags & VDisconCreate) {
+ /* printf("afs_GetParentVCache: deferring until parent exists\n"); */
+ code = EAGAIN;
+ goto end;
+ }
+
+end:
+ if (code && *adp) {
+ afs_PutVCache(*adp);
+ *adp = NULL;
+ }
+ return code;
+}
+
+
+/*!
* Handles file renaming on reconnection:
* - Get the old name from the old dir's shadow dir.
* - Get the new name from the current dir.
* - Old dir fid and new dir fid are collected along the way.
* */
-int afs_ProcessOpRename(struct vcache *avc, struct vrequest *areq)
+int
+afs_ProcessOpRename(struct vcache *avc, struct vrequest *areq)
{
struct VenusFid old_pdir_fid, new_pdir_fid;
- char *old_name, *new_name;
+ char *old_name = NULL, *new_name = NULL;
struct AFSFetchStatus OutOldDirStatus, OutNewDirStatus;
struct AFSVolSync tsync;
- struct conn *tc;
+ struct afs_conn *tc;
+ struct rx_connection *rxconn;
afs_uint32 code = 0;
XSTATS_DECLS;
/* Get old dir vcache. */
- old_pdir_fid.Cell = avc->fid.Cell;
- old_pdir_fid.Fid.Volume = avc->fid.Fid.Volume;
- old_pdir_fid.Fid.Vnode = avc->oldVnode;
- old_pdir_fid.Fid.Unique = avc->oldUnique;
+ old_pdir_fid.Cell = avc->f.fid.Cell;
+ old_pdir_fid.Fid.Volume = avc->f.fid.Fid.Volume;
+ old_pdir_fid.Fid.Vnode = avc->f.oldParent.vnode;
+ old_pdir_fid.Fid.Unique = avc->f.oldParent.unique;
/* Get old name. */
- old_name = (char *) afs_osi_Alloc(AFSNAMEMAX);
+ old_name = afs_osi_Alloc(AFSNAMEMAX);
if (!old_name) {
- printf("afs_ProcessOpRename: Couldn't alloc space for old name.\n");
+ /* printf("afs_ProcessOpRename: Couldn't alloc space for old name.\n"); */
return ENOMEM;
}
code = afs_GetVnodeName(avc, &old_pdir_fid, old_name, 1);
if (code) {
- printf("afs_ProcessOpRename: Couldn't find old name.\n");
- code = ENOENT;
- goto end2;
+ /* printf("afs_ProcessOpRename: Couldn't find old name.\n"); */
+ goto done;
}
/* Alloc data first. */
- new_name = (char *) afs_osi_Alloc(AFSNAMEMAX);
+ new_name = afs_osi_Alloc(AFSNAMEMAX);
if (!new_name) {
- printf("afs_ProcessOpRename: Couldn't alloc space for new name.\n");
+ /* printf("afs_ProcessOpRename: Couldn't alloc space for new name.\n"); */
code = ENOMEM;
- goto end2;
+ goto done;
}
- if (avc->ddirty_flags & VDisconRenameSameDir) {
+ if (avc->f.ddirty_flags & VDisconRenameSameDir) {
/* If we're in the same dir, don't do the lookups all over again,
* just copy fid and vcache from the old dir.
*/
memcpy(&new_pdir_fid, &old_pdir_fid, sizeof(struct VenusFid));
} else {
/* Get parent dir's FID.*/
- new_pdir_fid.Fid.Unique = 0;
- afs_GetParentDirFid(avc, &new_pdir_fid);
- if (!new_pdir_fid.Fid.Unique) {
- printf("afs_ProcessOpRename: Couldn't find new parent dir FID.\n");
- code = ENOENT;
- goto end1;
+ if (afs_GetParentDirFid(avc, &new_pdir_fid)) {
+ /* printf("afs_ProcessOpRename: Couldn't find new parent dir FID.\n"); */
+ code = ENETDOWN;
+ goto done;
}
}
/* And finally get the new name. */
code = afs_GetVnodeName(avc, &new_pdir_fid, new_name, 0);
if (code) {
- printf("afs_ProcessOpRename: Couldn't find new name.\n");
- code = ENOENT;
- goto end1;
+ /* printf("afs_ProcessOpRename: Couldn't find new name.\n"); */
+ goto done;
}
/* Send to data to server. */
do {
- tc = afs_Conn(&old_pdir_fid, areq, SHARED_LOCK);
+ tc = afs_Conn(&old_pdir_fid, areq, SHARED_LOCK, &rxconn);
if (tc) {
XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_RENAME);
RX_AFS_GUNLOCK();
- code = RXAFS_Rename(tc->id,
+ code = RXAFS_Rename(rxconn,
(struct AFSFid *)&old_pdir_fid.Fid,
old_name,
(struct AFSFid *)&new_pdir_fid.Fid,
code = -1;
} while (afs_Analyze(tc,
+ rxconn,
code,
&new_pdir_fid,
areq,
SHARED_LOCK,
NULL));
- if (code)
- printf("afs_ProcessOpRename: server code=%u\n", code);
-end1:
- afs_osi_Free(new_name, AFSNAMEMAX);
-end2:
- afs_osi_Free(old_name, AFSNAMEMAX);
+ /* if (code) printf("afs_ProcessOpRename: server code=%u\n", code); */
+done:
+ if (new_name)
+ afs_osi_Free(new_name, AFSNAMEMAX);
+ if (old_name)
+ afs_osi_Free(old_name, AFSNAMEMAX);
return code;
}
* - Handle errors.
* - Reorder vhash and dcaches in their hashes, using the newly acquired fid.
*/
-int afs_ProcessOpCreate(struct vcache *avc,
- struct vrequest *areq,
- struct AFS_UCRED *acred)
+int
+afs_ProcessOpCreate(struct vcache *avc, struct vrequest *areq,
+ afs_ucred_t *acred)
{
- char *tname = NULL;
+ char *tname = NULL, *ttargetName = NULL;
struct AFSStoreStatus InStatus;
struct AFSFetchStatus OutFidStatus, OutDirStatus;
struct VenusFid pdir_fid, newFid;
- struct server *hostp = NULL;
struct AFSCallBack CallBack;
struct AFSVolSync tsync;
struct vcache *tdp = NULL, *tvc = NULL;
struct dcache *tdc = NULL;
- struct conn *tc;
- afs_int32 now, hash, new_hash, index;
- int code = 0;
+ struct afs_conn *tc;
+ struct rx_connection *rxconn;
+ afs_int32 hash, new_hash, index;
+ afs_size_t tlen;
+ int code, op = 0;
XSTATS_DECLS;
- /* Get parent dir's FID. */
- pdir_fid.Fid.Unique = 0;
- afs_GetParentDirFid(avc, &pdir_fid);
- if (!pdir_fid.Fid.Unique) {
- printf("afs_ProcessOpCreate: Couldn't find parent dir'sFID.\n");
- return ENOENT;
- }
-
tname = afs_osi_Alloc(AFSNAMEMAX);
- if (!tname) {
- printf("afs_ProcessOpCreate: Couldn't find file name\n");
+ if (!tname)
return ENOMEM;
- }
+ memset(&InStatus, 0, sizeof(InStatus));
- /* Get vnode's name. */
- code = afs_GetVnodeName(avc, &pdir_fid, tname, 0);
- if (code) {
- printf("afs_ProcessOpCreate: Couldn't find file name\n");
- code = ENOENT;
+ code = afs_GetParentVCache(avc, 0, &pdir_fid, tname, &tdp);
+ if (code)
goto end;
- }
- /* Get parent dir vcache. */
- ObtainSharedLock(&afs_xvcache, 760);
- tdp = afs_FindVCache(&pdir_fid, 0, 1);
- ReleaseSharedLock(&afs_xvcache);
- if (!tdp) {
- printf("afs_ProcessOpCreate: Couldn't find parent dir's vcache\n");
- code = ENOENT;
- goto end;
- }
+ /* This data may also be in linkData, but then we have to deal with
+ * the joy of terminating NULLs and . and file modes. So just get
+ * it from the dcache where it won't have been fiddled with.
+ */
+ if (vType(avc) == VLNK) {
+ afs_size_t offset;
+ struct dcache *tdc;
+ struct osi_file *tfile;
+
+ tdc = afs_GetDCache(avc, 0, areq, &offset, &tlen, 0);
+ if (!tdc) {
+ code = ENETDOWN;
+ goto end;
+ }
- if (tdp->ddirty_flags & VDisconCreate) {
- /* If the parent dir has been created locally, defer
- * this vnode for later by moving it to the end.
- */
- afs_DDirtyVCList->ddirty_next = avc;
- afs_DDirtyVCList = avc;
- printf("afs_ProcessOpRemove: deferring this vcache\n");
- code = ENOTEMPTY;
- goto end;
+ if (tlen > 1024) {
+ afs_PutDCache(tdc);
+ code = EFAULT;
+ goto end;
+ }
+
+ tlen++; /* space for NULL */
+ ttargetName = afs_osi_Alloc(tlen);
+ if (!ttargetName) {
+ afs_PutDCache(tdc);
+ code = ENOMEM;
+ goto end;
+ }
+ ObtainReadLock(&tdc->lock);
+ tfile = afs_CFileOpen(&tdc->f.inode);
+ code = afs_CFileRead(tfile, 0, ttargetName, tlen);
+ ttargetName[tlen-1] = '\0';
+ afs_CFileClose(tfile);
+ ReleaseReadLock(&tdc->lock);
+ afs_PutDCache(tdc);
}
/* Set status. */
InStatus.Mask = AFS_SETMODTIME | AFS_SETMODE | AFS_SETGROUP;
- InStatus.ClientModTime = avc->m.Date;
- InStatus.Owner = avc->m.Owner;
- InStatus.Group = (afs_int32) acred->cr_gid;
+ InStatus.ClientModTime = avc->f.m.Date;
+ InStatus.Owner = avc->f.m.Owner;
+ InStatus.Group = (afs_int32) afs_cr_gid(acred);
/* Only care about protection bits. */
- InStatus.UnixModeBits = avc->m.Mode & 0xffff;
-
- /* Connect to server. */
- if (vType(avc) == VREG) {
- /* Make file on server. */
- do {
- tc = afs_Conn(&tdp->fid, areq, SHARED_LOCK);
- if (tc) {
- /* Remember for callback processing. */
- hostp = tc->srvr->server;
- now = osi_Time();
- XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_CREATEFILE);
+ InStatus.UnixModeBits = avc->f.m.Mode & 0xffff;
+
+ do {
+ tc = afs_Conn(&tdp->f.fid, areq, SHARED_LOCK, &rxconn);
+ if (tc) {
+ switch (vType(avc)) {
+ case VREG:
+ /* Make file on server. */
+ op = AFS_STATS_FS_RPCIDX_CREATEFILE;
+ XSTATS_START_TIME(op);
RX_AFS_GUNLOCK();
- code = RXAFS_CreateFile(tc->id,
- (struct AFSFid *)&tdp->fid.Fid,
- tname,
- &InStatus,
- (struct AFSFid *) &newFid.Fid,
- &OutFidStatus,
- &OutDirStatus,
- &CallBack,
- &tsync);
+ code = RXAFS_CreateFile(rxconn,
+ (struct AFSFid *)&tdp->f.fid.Fid,
+ tname, &InStatus,
+ (struct AFSFid *) &newFid.Fid,
+ &OutFidStatus, &OutDirStatus,
+ &CallBack, &tsync);
RX_AFS_GLOCK();
XSTATS_END_TIME;
- CallBack.ExpirationTime += now;
- } else
- code = -1;
- } while (afs_Analyze(tc,
- code,
- &tdp->fid,
- areq,
- AFS_STATS_FS_RPCIDX_CREATEFILE,
- SHARED_LOCK,
- NULL));
-
- } else if (vType(avc) == VDIR) {
- /* Make dir on server. */
- do {
- tc = afs_Conn(&tdp->fid, areq, SHARED_LOCK);
- if (tc) {
- XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_MAKEDIR);
- now = osi_Time();
+ break;
+ case VDIR:
+ /* Make dir on server. */
+ op = AFS_STATS_FS_RPCIDX_MAKEDIR;
+ XSTATS_START_TIME(op);
RX_AFS_GUNLOCK();
- code = RXAFS_MakeDir(tc->id,
- (struct AFSFid *) &tdp->fid.Fid,
- tname,
- &InStatus,
- (struct AFSFid *) &newFid.Fid,
- &OutFidStatus,
- &OutDirStatus,
- &CallBack,
- &tsync);
+ code = RXAFS_MakeDir(rxconn, (struct AFSFid *) &tdp->f.fid.Fid,
+ tname, &InStatus,
+ (struct AFSFid *) &newFid.Fid,
+ &OutFidStatus, &OutDirStatus,
+ &CallBack, &tsync);
RX_AFS_GLOCK();
XSTATS_END_TIME;
- CallBack.ExpirationTime += now;
- /* DON'T forget to set the callback at some point. */
- } else
- code = -1;
- } while (afs_Analyze(tc,
- code,
- &tdp->fid,
- areq,
- AFS_STATS_FS_RPCIDX_MAKEDIR,
- SHARED_LOCK,
- NULL));
- } /* Do server changes. */
+ break;
+ case VLNK:
+ /* Make symlink on server. */
+ op = AFS_STATS_FS_RPCIDX_SYMLINK;
+ XSTATS_START_TIME(op);
+ RX_AFS_GUNLOCK();
+ code = RXAFS_Symlink(rxconn,
+ (struct AFSFid *) &tdp->f.fid.Fid,
+ tname, ttargetName, &InStatus,
+ (struct AFSFid *) &newFid.Fid,
+ &OutFidStatus, &OutDirStatus, &tsync);
+ RX_AFS_GLOCK();
+ XSTATS_END_TIME;
+ break;
+ default:
+ op = AFS_STATS_FS_RPCIDX_CREATEFILE;
+ code = 1;
+ break;
+ }
+ } else
+ code = -1;
+ } while (afs_Analyze(tc, rxconn, code, &tdp->f.fid, areq, op, SHARED_LOCK, NULL));
/* TODO: Handle errors. */
if (code) {
- printf("afs_ProcessOpCreate: error while creating vnode on server, code=%d .\n", code);
- code = EIO;
+ /* printf("afs_ProcessOpCreate: error while creating vnode on server, code=%d .\n", code); */
goto end;
}
/* The rpc doesn't set the cell number. */
- newFid.Cell = avc->fid.Cell;
+ newFid.Cell = avc->f.fid.Cell;
/*
* Change the fid in the dir entry.
*/
/* Seek the dir's dcache. */
- tdc = afs_FindDCacheByFid(&tdp->fid);
+ tdc = afs_FindDCacheByFid(&tdp->f.fid);
if (tdc) {
/* And now change the fid in the parent dir entry. */
- afs_dir_ChangeFid(tdc, tname, &avc->fid.Fid.Vnode, &newFid.Fid.Vnode);
+ afs_dir_ChangeFid(tdc, tname, &avc->f.fid.Fid.Vnode, &newFid.Fid.Vnode);
afs_PutDCache(tdc);
}
/* Change fid in the dir for the "." entry. ".." has alredy been
* handled by afs_FixChildrenFids when processing the parent dir.
*/
- tdc = afs_FindDCacheByFid(&avc->fid);
+ tdc = afs_FindDCacheByFid(&avc->f.fid);
if (tdc) {
- afs_dir_ChangeFid(tdc, ".", &avc->fid.Fid.Vnode, &newFid.Fid.Vnode);
+ afs_dir_ChangeFid(tdc, ".", &avc->f.fid.Fid.Vnode,
+ &newFid.Fid.Vnode);
- if (avc->m.LinkCount >= 2)
- /* For non empty dirs, fix children's parentVnode and parentUnique
- * reference.
+ if (avc->f.m.LinkCount >= 2)
+ /* For non empty dirs, fix children's parentVnode and
+ * parentUnique reference.
*/
- afs_FixChildrenFids(&avc->fid, &newFid);
+ afs_FixChildrenFids(&avc->f.fid, &newFid);
afs_PutDCache(tdc);
}
ObtainWriteLock(&afs_xvcache, 735);
/* Old fid hash. */
- hash = VCHash(&avc->fid);
+ hash = VCHash(&avc->f.fid);
/* New fid hash. */
new_hash = VCHash(&newFid);
afs_vhashT[hash] = avc->hnext;
} else {
/* More elements in hash chain. */
- //for (tvc = afs_vhashT[hash]; tdp; tdp = tdp->hnext) {
for (tvc = afs_vhashT[hash]; tvc; tvc = tvc->hnext) {
if (tvc->hnext == avc) {
tvc->hnext = avc->hnext;
}
}
} /* if (!afs_vhashT[i]->hnext) */
- QRemove(&afs_vhashTV[hash]);
+ QRemove(&avc->vhashq);
/* Insert hash in new position. */
avc->hnext = afs_vhashT[new_hash];
afs_vhashT[new_hash] = avc;
- QAdd(&afs_vhashTV[new_hash], &avc->vhashq);
+ QAdd(&afs_vhashTV[VCHashV(&newFid)], &avc->vhashq);
ReleaseWriteLock(&afs_xvcache);
/* Do the same thing for all dcaches. */
- hash = DVHash(&avc->fid);
+ hash = DVHash(&avc->f.fid);
ObtainWriteLock(&afs_xdcache, 743);
for (index = afs_dvhashTbl[hash]; index != NULLIDX; index = hash) {
hash = afs_dvnextTbl[index];
- tdc = afs_GetDSlot(index, NULL);
+ tdc = afs_GetValidDSlot(index);
ReleaseReadLock(&tdc->tlock);
- if (afs_indexUnique[index] == avc->fid.Fid.Unique) {
- if (!FidCmp(&tdc->f.fid, &avc->fid)) {
+ if (afs_indexUnique[index] == avc->f.fid.Fid.Unique) {
+ if (!FidCmp(&tdc->f.fid, &avc->f.fid)) {
/* Safer but slower. */
afs_HashOutDCache(tdc, 0);
afs_indexUnique[tdc->index] = newFid.Fid.Unique;
memcpy(&tdc->f.fid, &newFid, sizeof(struct VenusFid));
- //afs_MaybeWakeupTruncateDaemon();
} /* if fid match */
} /* if uniquifier match */
if (tdc)
ReleaseWriteLock(&afs_xdcache);
/* Now we can set the new fid. */
- memcpy(&avc->fid, &newFid, sizeof(struct VenusFid));
+ memcpy(&avc->f.fid, &newFid, sizeof(struct VenusFid));
- if (tdp) {
- /* Unset parent dir CStat flag, so it will get refreshed on next
- * online stat.
- */
- ObtainWriteLock(&tdp->lock, 745);
- tdp->states &= ~CStatd;
- ReleaseWriteLock(&tdp->lock);
- }
end:
if (tdp)
afs_PutVCache(tdp);
afs_osi_Free(tname, AFSNAMEMAX);
+ if (ttargetName)
+ afs_osi_Free(ttargetName, tlen);
return code;
}
/*!
* Remove a vnode on the server, be it file or directory.
* Not much to do here only get the parent dir's fid and call the
- * removel rpc.
+ * removal rpc.
*
* \param avc The deleted vcache
* \param areq
*
* \note avc must be write locked.
*/
-int afs_ProcessOpRemove(struct vcache *avc, struct vrequest *areq)
+int
+afs_ProcessOpRemove(struct vcache *avc, struct vrequest *areq)
{
char *tname = NULL;
struct AFSFetchStatus OutDirStatus;
struct VenusFid pdir_fid;
struct AFSVolSync tsync;
- struct conn *tc;
+ struct afs_conn *tc;
+ struct rx_connection *rxconn;
struct vcache *tdp = NULL;
int code = 0;
XSTATS_DECLS;
- /* Get parent dir's FID. */
- pdir_fid.Fid.Unique = 0;
- afs_GetParentDirFid(avc, &pdir_fid);
- if (!pdir_fid.Fid.Unique) {
- printf("afs_ProcessOpRemove: Couldn't find parent dir's FID.\n");
- return ENOENT;
- }
-
tname = afs_osi_Alloc(AFSNAMEMAX);
if (!tname) {
- printf("afs_ProcessOpRemove: Couldn't find file name\n");
+ /* printf("afs_ProcessOpRemove: Couldn't alloc space for file name\n"); */
return ENOMEM;
}
- /* Get file name. */
- code = afs_GetVnodeName(avc, &pdir_fid, tname, 1);
- if (code) {
- printf("afs_ProcessOpRemove: Couldn't find file name\n");
- code = ENOENT;
+ code = afs_GetParentVCache(avc, 1, &pdir_fid, tname, &tdp);
+ if (code)
goto end;
- }
if ((vType(avc) == VDIR) && (afs_CheckDeletedChildren(avc))) {
/* Deleted children of this dir remain unsynchronized.
* Defer this vcache.
*/
- afs_DDirtyVCList->ddirty_next = avc;
- afs_DDirtyVCList = avc;
- code = ENOTEMPTY;
+ code = EAGAIN;
goto end;
}
- if (vType(avc) == VREG) {
+ if (vType(avc) == VREG || vType(avc) == VLNK) {
/* Remove file on server. */
do {
- tc = afs_Conn(&pdir_fid, areq, SHARED_LOCK);
+ tc = afs_Conn(&pdir_fid, areq, SHARED_LOCK, &rxconn);
if (tc) {
XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
RX_AFS_GUNLOCK();
- code = RXAFS_RemoveFile(tc->id,
+ code = RXAFS_RemoveFile(rxconn,
&pdir_fid.Fid,
tname,
&OutDirStatus,
} else
code = -1;
} while (afs_Analyze(tc,
+ rxconn,
code,
&pdir_fid,
areq,
} else if (vType(avc) == VDIR) {
/* Remove dir on server. */
do {
- tc = afs_Conn(&pdir_fid, areq, SHARED_LOCK);
+ tc = afs_Conn(&pdir_fid, areq, SHARED_LOCK, &rxconn);
if (tc) {
XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEDIR);
RX_AFS_GUNLOCK();
- code = RXAFS_RemoveDir(tc->id,
+ code = RXAFS_RemoveDir(rxconn,
&pdir_fid.Fid,
tname,
&OutDirStatus,
} else
code = -1;
} while (afs_Analyze(tc,
+ rxconn,
code,
&pdir_fid,
areq,
} /* if (vType(avc) == VREG) */
- if (code)
- printf("afs_ProcessOpRemove: server returned code=%u\n", code);
+ /* if (code) printf("afs_ProcessOpRemove: server returned code=%u\n", code); */
- /* Remove the statd flag from parent dir's vcache. */
- ObtainSharedLock(&afs_xvcache, 761);
- tdp = afs_FindVCache(&pdir_fid, 0, 1);
- ReleaseSharedLock(&afs_xvcache);
- if (tdp) {
- ObtainWriteLock(&tdp->lock, 746);
- tdp->states &= ~CStatd;
- ReleaseWriteLock(&tdp->lock);
- afs_PutVCache(tdp);
- }
end:
afs_osi_Free(tname, AFSNAMEMAX);
return code;
*
* \return 0 for success. On failure, other error codes.
*/
-int afs_SendChanges(struct vcache *avc, struct vrequest *areq)
+int
+afs_SendChanges(struct vcache *avc, struct vrequest *areq)
{
- struct conn *tc;
+ struct afs_conn *tc;
+ struct rx_connection *rxconn;
struct AFSStoreStatus sstat;
struct AFSFetchStatus fstat;
struct AFSVolSync tsync;
XSTATS_DECLS;
/* Start multiplexing dirty operations from ddirty_flags field: */
- if (avc->ddirty_flags & VDisconSetAttrMask) {
+ if (avc->f.ddirty_flags & VDisconSetAttrMask) {
/* Setattr OPS: */
/* Turn dirty vc data into a new store status... */
if (afs_GenStoreStatus(avc, &sstat) > 0) {
do {
- tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
+ tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK, &rxconn);
if (tc) {
/* ... and send it. */
XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STORESTATUS);
RX_AFS_GUNLOCK();
- code = RXAFS_StoreStatus(tc->id,
- (struct AFSFid *) &avc->fid.Fid,
+ code = RXAFS_StoreStatus(rxconn,
+ (struct AFSFid *) &avc->f.fid.Fid,
&sstat,
&fstat,
&tsync);
code = -1;
} while (afs_Analyze(tc,
+ rxconn,
code,
- &avc->fid,
+ &avc->f.fid,
areq,
AFS_STATS_FS_RPCIDX_STORESTATUS,
SHARED_LOCK,
if (code)
return code;
- if (avc->ddirty_flags &
+ if (avc->f.ddirty_flags &
(VDisconTrunc
| VDisconWriteClose
| VDisconWriteFlush
/* Truncate OP: */
do {
- tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
+ tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK, &rxconn);
if (tc) {
/* Set storing flags. XXX: A tad inefficient ... */
- if (avc->ddirty_flags & VDisconWriteClose)
+ if (avc->f.ddirty_flags & VDisconWriteClose)
flags |= AFS_LASTSTORE;
- if (avc->ddirty_flags & VDisconWriteOsiFlush)
+ if (avc->f.ddirty_flags & VDisconWriteOsiFlush)
flags |= (AFS_SYNC | AFS_LASTSTORE);
- if (avc->ddirty_flags & VDisconWriteFlush)
+ if (avc->f.ddirty_flags & VDisconWriteFlush)
flags |= AFS_SYNC;
/* Try to send store to server. */
code = -1;
} while (afs_Analyze(tc,
+ rxconn,
code,
- &avc->fid,
+ &avc->f.fid,
areq,
AFS_STATS_FS_RPCIDX_STOREDATA,
SHARED_LOCK,
* \param acred User credentials.
*
* \return If all files synchronized succesfully, return 0, otherwise
- * return 1.
+ * return error code
*
* \note For now, it's the request from the PDiscon pioctl.
*
*/
-int afs_ResyncDisconFiles(struct vrequest *areq, struct AFS_UCRED *acred)
+int
+afs_ResyncDisconFiles(struct vrequest *areq, afs_ucred_t *acred)
{
- struct conn *tc;
- struct vcache *tvc, *tmp;
+ struct afs_conn *tc;
+ struct rx_connection *rxconn;
+ struct vcache *tvc;
struct AFSFetchStatus fstat;
struct AFSCallBack callback;
struct AFSVolSync tsync;
- struct vcache *shList, *shListStart;
- int code;
- int sync_failed = 0;
- int ret_code = 0;
- int defered = 0;
+ int code = 0;
afs_int32 start = 0;
XSTATS_DECLS;
- //AFS_STATCNT(afs_ResyncDisconFiles);
+ /*AFS_STATCNT(afs_ResyncDisconFiles);*/
- shList = shListStart = NULL;
+ ObtainWriteLock(&afs_disconDirtyLock, 707);
- ObtainReadLock(&afs_DDirtyVCListLock);
+ while (!QEmpty(&afs_disconDirty)) {
+ tvc = QEntry(QPrev(&afs_disconDirty), struct vcache, dirtyq);
- tvc = afs_DDirtyVCListStart;
- while (tvc) {
+ /* Can't lock tvc whilst holding the discon dirty lock */
+ ReleaseWriteLock(&afs_disconDirtyLock);
/* Get local write lock. */
- ObtainWriteLock(&tvc->lock, 704);
- sync_failed = 0;
-
- if ((tvc->ddirty_flags & VDisconRemove) &&
- (tvc->ddirty_flags & VDisconCreate)) {
- /* Data created and deleted locally. The server doesn't
- * need to know about this, so we'll just skip this file
- * from the dirty list.
- */
- goto skip_file;
+ ObtainWriteLock(&tvc->lock, 705);
- } else if (tvc->ddirty_flags & VDisconRemove) {
+ if (tvc->f.ddirty_flags & VDisconRemove) {
/* Delete the file on the server and just move on
* to the next file. After all, it has been deleted
* we can't replay any other operation it.
*/
code = afs_ProcessOpRemove(tvc, areq);
- if (code == ENOTEMPTY)
- defered = 1;
- goto skip_file;
+ goto next_file;
- } else if (tvc->ddirty_flags & VDisconCreate) {
+ } else if (tvc->f.ddirty_flags & VDisconCreate) {
/* For newly created files, we don't need a server lock. */
code = afs_ProcessOpCreate(tvc, areq, acred);
- if (code == ENOTEMPTY)
- defered = 1;
if (code)
- goto skip_file;
- }
+ goto next_file;
+ tvc->f.ddirty_flags &= ~VDisconCreate;
+ tvc->f.ddirty_flags |= VDisconCreated;
+ }
+#if 0
/* Get server write lock. */
do {
- tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
+ tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK, &rxconn);
if (tc) {
XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETLOCK);
RX_AFS_GUNLOCK();
- code = RXAFS_SetLock(tc->id,
- (struct AFSFid *)&tvc->fid.Fid,
+ code = RXAFS_SetLock(rxconn,
+ (struct AFSFid *)&tvc->f.fid.Fid,
LockWrite,
&tsync);
RX_AFS_GLOCK();
code = -1;
} while (afs_Analyze(tc,
+ rxconn,
code,
- &tvc->fid,
+ &tvc->f.fid,
areq,
AFS_STATS_FS_RPCIDX_SETLOCK,
SHARED_LOCK,
NULL));
- if (code) {
- sync_failed = 1;
- goto skip_file;
- }
-
- if ((tvc->ddirty_flags & VDisconRename) &&
- !(tvc->ddirty_flags & VDisconCreate)) {
- /* Rename file only if it hasn't been created locally. */
+ if (code)
+ goto next_file;
+#endif
+ if (tvc->f.ddirty_flags & VDisconRename) {
+ /* If we're renaming the file, do so now */
code = afs_ProcessOpRename(tvc, areq);
if (code)
- goto skip_file;
+ goto unlock_srv_file;
}
/* Issue a FetchStatus to get info about DV and callbacks. */
do {
- tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
+ tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK, &rxconn);
if (tc) {
- tvc->callback = tc->srvr->server;
+ tvc->callback = tc->parent->srvr->server;
start = osi_Time();
XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHSTATUS);
RX_AFS_GUNLOCK();
- code = RXAFS_FetchStatus(tc->id,
- (struct AFSFid *)&tvc->fid.Fid,
+ code = RXAFS_FetchStatus(rxconn,
+ (struct AFSFid *)&tvc->f.fid.Fid,
&fstat,
&callback,
&tsync);
code = -1;
} while (afs_Analyze(tc,
+ rxconn,
code,
- &tvc->fid,
+ &tvc->f.fid,
areq,
AFS_STATS_FS_RPCIDX_FETCHSTATUS,
SHARED_LOCK,
NULL));
if (code) {
- sync_failed = 1;
goto unlock_srv_file;
}
- if ((dv_match(tvc, fstat) && (tvc->m.Date == fstat.ServerModTime)) ||
+ if ((dv_match(tvc, fstat) && (tvc->f.m.Date == fstat.ServerModTime)) ||
(afs_ConflictPolicy == CLIENT_WINS) ||
- (tvc->ddirty_flags & VDisconCreate)) {
+ (tvc->f.ddirty_flags & VDisconCreated)) {
/*
* Send changes to the server if there's data version match, or
* client wins policy has been selected or file has been created
* XXX: Checking server attr changes by timestamp might not the
* most elegant solution, but it's the most viable one that we could find.
*/
- afs_UpdateStatus(tvc, &tvc->fid, areq, &fstat, &callback, start);
+ afs_UpdateStatus(tvc, &tvc->f.fid, areq, &fstat, &callback, start);
code = afs_SendChanges(tvc, areq);
} else if (afs_ConflictPolicy == SERVER_WINS) {
/* DV mismatch, apply collision resolution policy. */
- /* Dequeue whatever callback is on top (XXX: propably none). */
- ObtainWriteLock(&afs_xcbhash, 706);
- afs_DequeueCallback(tvc);
- tvc->callback = NULL;
- tvc->states &= ~(CStatd | CDirty | CUnique);
- ReleaseWriteLock(&afs_xcbhash);
-
- /* Save metadata. File length gets updated as well because we
- * just removed CDirty from the avc.
- */
- //afs_ProcessFS(tvc, &fstat, areq);
-
/* Discard this files chunks and remove from current dir. */
- afs_TryToSmush(tvc, acred, 1);
- osi_dnlc_purgedp(tvc);
- if (tvc->linkData && !(tvc->states & CCore)) {
- /* Take care of symlinks. */
- afs_osi_Free(tvc->linkData, strlen(tvc->linkData) + 1);
- tvc->linkData = NULL;
- }
-
- /* Otherwise file content's won't be synchronized. */
- tvc->truncPos = AFS_NOTRUNC;
-
+ afs_ResetVCache(tvc, acred, 0);
+ tvc->f.truncPos = AFS_NOTRUNC;
} else {
- printf("afs_ResyncDisconFiles: no resolution policy selected.\n");
+ /* printf("afs_ResyncDisconFiles: no resolution policy selected.\n"); */
} /* if DV match or client wins policy */
- if (code) {
- sync_failed = 1;
- printf("Sync FAILED.\n");
- }
-
unlock_srv_file:
/* Release server write lock. */
+#if 0
do {
- tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
+ tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK, &rxconn);
if (tc) {
XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_RELEASELOCK);
RX_AFS_GUNLOCK();
- code = RXAFS_ReleaseLock(tc->id,
- (struct AFSFid *) &tvc->fid.Fid,
+ ucode = RXAFS_ReleaseLock(rxconn,
+ (struct AFSFid *) &tvc->f.fid.Fid,
&tsync);
RX_AFS_GLOCK();
XSTATS_END_TIME;
} else
- code = -1;
+ ucode = -1;
} while (afs_Analyze(tc,
- code,
- &tvc->fid,
+ rxconn,
+ ucode,
+ &tvc->f.fid,
areq,
AFS_STATS_FS_RPCIDX_RELEASELOCK,
SHARED_LOCK,
NULL));
-
-skip_file:
- /* Pop this dirty vc out. */
- tmp = tvc;
- tvc = tvc->ddirty_next;
-
- if (!defered) {
- /* Vnode not deferred. Clean it up. */
- if (!sync_failed) {
- if (tmp->ddirty_flags == VDisconShadowed) {
- /* Dirs that have only the shadow flag set might still
- * be used so keep them in a different list, that gets
- * deleted after resync is done.
- */
- if (!shListStart)
- shListStart = shList = tmp;
- else {
- shList->ddirty_next = tmp;
- shList = tmp;
- }
- } else if (tmp->ddirty_flags & VDisconShadowed)
- /* We can discard the shadow dir now. */
- afs_DeleteShadowDir(tmp);
-
- /* Drop the refcount on this vnode because it's not in the
- * list anymore.
- */
- afs_PutVCache(tmp);
-
- /* Only if sync was successfull,
- * clear flags and dirty references.
- */
- tmp->ddirty_next = NULL;
- tmp->ddirty_flags = 0;
- } else
- ret_code = 1;
+#endif
+next_file:
+ ObtainWriteLock(&afs_disconDirtyLock, 710);
+ if (code == 0) {
+ /* Replayed successfully - pull the vcache from the
+ * disconnected list */
+ tvc->f.ddirty_flags = 0;
+ QRemove(&tvc->dirtyq);
+ afs_PutVCache(tvc);
} else {
- tmp->ddirty_next = NULL;
- defered = 0;
- } /* if (!defered) */
+ if (code == EAGAIN) {
+ /* Operation was deferred. Pull it from the current place in
+ * the list, and stick it at the end again */
+ QRemove(&tvc->dirtyq);
+ QAdd(&afs_disconDirty, &tvc->dirtyq);
+ } else {
+ /* Failed - keep state as is, and let the user know we died */
+
+ ReleaseWriteLock(&tvc->lock);
+ break;
+ }
+ }
/* Release local write lock. */
- ReleaseWriteLock(&tmp->lock);
+ ReleaseWriteLock(&tvc->lock);
} /* while (tvc) */
- /* Delete the rest of shadow dirs. */
- tvc = shListStart;
- while (tvc) {
- ObtainWriteLock(&tvc->lock, 764);
+ if (code) {
+ ReleaseWriteLock(&afs_disconDirtyLock);
+ return code;
+ }
- afs_DeleteShadowDir(tvc);
- tvc->shVnode = 0;
- tvc->shUnique = 0;
+ /* Dispose of all of the shadow directories */
+ afs_DisconDiscardAllShadows(0, acred);
- tmp = tvc;
- tvc = tvc->ddirty_next;
- tmp->ddirty_next = NULL;
+ ReleaseWriteLock(&afs_disconDirtyLock);
+ return code;
+}
- ReleaseWriteLock(&tmp->lock);
+/*!
+ * Discard all of our shadow directory copies. If squash is true, then
+ * we also invalidate the vcache holding the shadow directory, to ensure
+ * that any disconnected changes are deleted
+ *
+ * \param squash
+ * \param acred
+ *
+ * \note afs_disconDirtyLock must be held on entry. It will be released
+ * and reobtained
+ */
+
+static void
+afs_DisconDiscardAllShadows(int squash, afs_ucred_t *acred)
+{
+ struct vcache *tvc;
+
+ while (!QEmpty(&afs_disconShadow)) {
+ tvc = QEntry(QNext(&afs_disconShadow), struct vcache, shadowq);
+
+ /* Must release the dirty lock to be able to get a vcache lock */
+ ReleaseWriteLock(&afs_disconDirtyLock);
+ ObtainWriteLock(&tvc->lock, 706);
+
+ if (squash)
+ afs_ResetVCache(tvc, acred, 0);
+
+ afs_DeleteShadowDir(tvc);
+
+ ReleaseWriteLock(&tvc->lock);
+ ObtainWriteLock(&afs_disconDirtyLock, 709);
} /* while (tvc) */
+}
+
+/*!
+ * This function throws away the whole disconnected state, allowing
+ * the cache manager to reconnect to a server if we get into a state
+ * where reconiliation is impossible.
+ *
+ * \param acred
+ *
+ */
+void
+afs_DisconDiscardAll(afs_ucred_t *acred)
+{
+ struct vcache *tvc;
- if (ret_code == 0) {
- /* NULLIFY dirty list only if resync complete. */
- afs_DDirtyVCListStart = NULL;
- afs_DDirtyVCList = NULL;
+ ObtainWriteLock(&afs_disconDirtyLock, 717);
+ while (!QEmpty(&afs_disconDirty)) {
+ tvc = QEntry(QPrev(&afs_disconDirty), struct vcache, dirtyq);
+ QRemove(&tvc->dirtyq);
+ ReleaseWriteLock(&afs_disconDirtyLock);
+
+ ObtainWriteLock(&tvc->lock, 718);
+ afs_ResetVCache(tvc, acred, 0);
+ tvc->f.truncPos = AFS_NOTRUNC;
+ ReleaseWriteLock(&tvc->lock);
+ ObtainWriteLock(&afs_disconDirtyLock, 719);
+ afs_PutVCache(tvc);
}
- ReleaseReadLock(&afs_DDirtyVCListLock);
- return ret_code;
+ afs_DisconDiscardAllShadows(1, acred);
+
+ ReleaseWriteLock(&afs_disconDirtyLock);
}
/*!
*
* \note Call with afs_DDirtyVCListLock read locked.
*/
-void afs_DbgDisconFiles()
+void
+afs_DbgDisconFiles(void)
{
struct vcache *tvc;
+ struct afs_q *q;
int i = 0;
- tvc = afs_DDirtyVCListStart;
- printf("List of dirty files: \n");
- while (tvc) {
- printf("Cell=%u Volume=%u VNode=%u Unique=%u\n",
- tvc->fid.Cell,
- tvc->fid.Fid.Volume,
- tvc->fid.Fid.Vnode,
- tvc->fid.Fid.Unique);
- tvc = tvc->ddirty_next;
+ afs_warn("List of dirty files: \n");
+
+ ObtainReadLock(&afs_disconDirtyLock);
+ for (q = QPrev(&afs_disconDirty); q != &afs_disconDirty; q = QPrev(q)) {
+ tvc = QEntry(q, struct vcache, dirtyq);
+
+ afs_warn("Cell=%u Volume=%u VNode=%u Unique=%u\n",
+ tvc->f.fid.Cell,
+ tvc->f.fid.Fid.Volume,
+ tvc->f.fid.Fid.Vnode,
+ tvc->f.fid.Fid.Unique);
+
i++;
if (i >= 30)
osi_Panic("afs_DbgDisconFiles: loop in dirty list\n");
}
+ ReleaseReadLock(&afs_disconDirtyLock);
}
/*!
*
* \note Don't forget to fill in afid with Cell and Volume.
*/
-void afs_GenShadowFid(struct VenusFid *afid)
+void
+afs_GenShadowFid(struct VenusFid *afid)
{
afs_uint32 i, index, max_unique = 1;
struct vcache *tvc = NULL;
/* Try generating a fid that isn't used in the vhash. */
do {
+ /* Shadow Fids are always directories */
afid->Fid.Vnode = afs_DisconVnode + 1;
i = DVHash(afid);
* afs_DisconVNode and the uniquifier by getting the highest
* uniquifier on a hash chain and incrementing it by one.
*
- * \param avc afid The fid structre that will be filled.
+ * \param afid The fid structre that will be filled.
* \param avtype Vnode type: VDIR/VREG.
+ * \param lock True indicates that xvcache may be obtained,
+ * False that it is already held
*
* \note The cell number must be completed somewhere else.
*/
-void afs_GenFakeFid(struct VenusFid *afid, afs_uint32 avtype)
+void
+afs_GenFakeFid(struct VenusFid *afid, afs_uint32 avtype, int lock)
{
struct vcache *tvc;
- afs_uint32 max_unique = 1, i;
+ afs_uint32 max_unique = 0, i;
- if (avtype == VDIR)
+ switch (avtype) {
+ case VDIR:
afid->Fid.Vnode = afs_DisconVnode + 1;
- else if (avtype == VREG)
+ break;
+ case VREG:
+ case VLNK:
afid->Fid.Vnode = afs_DisconVnode;
+ break;
+ }
- ObtainWriteLock(&afs_xvcache, 736);
+ if (lock)
+ ObtainWriteLock(&afs_xvcache, 736);
i = VCHash(afid);
for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
- if (tvc->fid.Fid.Unique > max_unique)
- max_unique = tvc->fid.Fid.Unique;
+ if (tvc->f.fid.Fid.Unique > max_unique)
+ max_unique = tvc->f.fid.Fid.Unique;
}
- ReleaseWriteLock(&afs_xvcache);
+ if (lock)
+ ReleaseWriteLock(&afs_xvcache);
afid->Fid.Unique = max_unique + 1;
afs_DisconVnode += 2;
*
* \note Call with avc write locked.
*/
-void afs_GenDisconStatus(
- struct vcache *adp,
- struct vcache *avc,
- struct VenusFid *afid,
- struct vattr *attrs,
- struct vrequest *areq,
- int file_type)
+void
+afs_GenDisconStatus(struct vcache *adp, struct vcache *avc,
+ struct VenusFid *afid, struct vattr *attrs,
+ struct vrequest *areq, int file_type)
{
- memcpy(&avc->fid, afid, sizeof(struct VenusFid));
- avc->m.Mode = attrs->va_mode;
+ afs_hyper_t zero;
+ memcpy(&avc->f.fid, afid, sizeof(struct VenusFid));
+ avc->f.m.Mode = attrs->va_mode;
/* Used to do this:
- * avc->m.Owner = attrs->va_uid;
+ * avc->f.m.Owner = attrs->va_uid;
* But now we use the parent dir's ownership,
* there's no other way to get a server owner id.
* XXX: Does it really matter?
*/
- avc->m.Group = adp->m.Group;
- avc->m.Owner = adp->m.Owner;
- hset64(avc->m.DataVersion, 0, 0);
- avc->m.Length = attrs->va_size;
- avc->m.Date = osi_Time();
- if (file_type == VREG) {
- vSetType(avc, VREG);
- avc->m.Mode |= S_IFREG;
- avc->m.LinkCount = 1;
- } else if (file_type == VDIR) {
+ avc->f.m.Group = adp->f.m.Group;
+ avc->f.m.Owner = adp->f.m.Owner;
+ hzero(zero);
+ afs_SetDataVersion(avc, &zero);
+ avc->f.m.Length = attrs->va_size;
+ avc->f.m.Date = osi_Time();
+ switch(file_type) {
+ case VREG:
+ vSetType(avc, VREG);
+ avc->f.m.Mode |= S_IFREG;
+ avc->f.m.LinkCount = 1;
+ avc->f.parent.vnode = adp->f.fid.Fid.Vnode;
+ avc->f.parent.unique = adp->f.fid.Fid.Unique;
+ break;
+ case VDIR:
vSetType(avc, VDIR);
- avc->m.Mode |= S_IFDIR;
- avc->m.LinkCount = 2;
+ avc->f.m.Mode |= S_IFDIR;
+ avc->f.m.LinkCount = 2;
+ break;
+ case VLNK:
+ vSetType(avc, VLNK);
+ avc->f.m.Mode |= S_IFLNK;
+ if ((avc->f.m.Mode & 0111) == 0)
+ avc->mvstat = AFS_MVSTAT_MTPT;
+ avc->f.parent.vnode = adp->f.fid.Fid.Vnode;
+ avc->f.parent.unique = adp->f.fid.Fid.Unique;
+ break;
+ default:
+ break;
}
-
- avc->anyAccess = adp->anyAccess;
+ avc->f.anyAccess = adp->f.anyAccess;
afs_AddAxs(avc->Access, areq->uid, adp->Access->axess);
avc->callback = NULL;
- avc->states |= CStatd;
- avc->states &= ~CBulkFetching;
+ avc->f.states |= CStatd;
+ avc->f.states &= ~CBulkFetching;
}
-#endif