#ifndef __CM_SCACHE_H_ENV__
#define __CM_SCACHE_H_ENV__ 1
+#define MOUNTPOINTLEN 1024
+
typedef struct cm_fid {
unsigned long cell;
unsigned long volume;
unsigned long unique;
} cm_fid_t;
-typedef struct cm_accessCache {
- osi_queue_t q; /* queue header */
- struct cm_user *userp; /* user having access rights */
- long rights; /* rights */
-} cm_accessCache_t;
+/* Key used for byte range locking. Each unique key identifies a
+ unique client per cm_scache_t for the purpose of locking. */
+typedef afs_uint64 cm_key_t;
+
+typedef struct cm_range {
+ afs_int64 offset;
+ afs_int64 length;
+} cm_range_t;
+
+/* forward dcls */
+struct cm_scache;
+typedef struct cm_scache cm_scache_t;
typedef struct cm_file_lock {
- osi_queue_t q; /* list of all locks */
- osi_queue_t fileq; /* per-file list of locks */
- cm_user_t *userp;
- LARGE_INTEGER LOffset;
- LARGE_INTEGER LLength;
- cm_fid_t fid;
- unsigned char LockType;
- unsigned char flags;
+ osi_queue_t q; /* list of all locks [protected by
+ cm_scacheLock] */
+ osi_queue_t fileq; /* per-file list of locks [protected
+ by scp->mx]*/
+
+ cm_user_t *userp; /* The user to which this lock belongs
+ to [immutable; held] */
+ cm_scache_t *scp; /* The scache to which this lock
+ applies to [immutable; held] */
+#ifdef DEBUG
+ cm_fid_t fid;
+#endif
+
+ cm_range_t range; /* Range for the lock [immutable] */
+ cm_key_t key; /* Key for the lock [immutable] */
+ unsigned char lockType; /* LockRead or LockWrite [immutable] */
+ unsigned char flags; /* combination of CM_FILELOCK_FLAG__*
+ * [protected by cm_scacheLock] */
+ time_t lastUpdate; /* time of last assertion with
+ * server. [protected by
+ * cm_scacheLock] */
} cm_file_lock_t;
-#define CM_FILELOCK_FLAG_INVALID 0x1
-#define CM_FILELOCK_FLAG_WAITING 0x2
+#define CM_FILELOCK_FLAG_DELETED 0x01
+#define CM_FILELOCK_FLAG_LOST 0x02
+
+/* the following are mutually exclusive */
+#define CM_FILELOCK_FLAG_WAITLOCK 0x04
+#define CM_FILELOCK_FLAG_WAITUNLOCK 0x0C
+
+/* the following is used to indicate that there are no server side
+ locks associated with this lock. This is true for locks obtained
+ against files in RO volumes as well as files residing on servers
+ that disable client side byte range locking. */
+#define CM_FILELOCK_FLAG_CLIENTONLY 0x10
+
+#define CM_FLSHARE_OFFSET_HIGH 0x01000000
+#define CM_FLSHARE_OFFSET_LOW 0x00000000
+#define CM_FLSHARE_LENGTH_HIGH 0x00000000
+#define CM_FLSHARE_LENGTH_LOW 0x00000001
typedef struct cm_prefetch { /* last region scanned for prefetching */
osi_hyper_t base; /* start of region */
osi_hyper_t end; /* first char past region */
} cm_prefetch_t;
+#define CM_SCACHE_MAGIC ('S' | 'C'<<8 | 'A'<<16 | 'C'<<24)
+
typedef struct cm_scache {
- osi_queue_t q; /* lru queue; cm_scacheLock */
- struct cm_scache *nextp; /* next in hash; cm_scacheLock */
- cm_fid_t fid;
- long flags; /* flags; locked by mx */
-
- /* synchronization stuff */
- osi_mutex_t mx; /* mutex for this structure */
- osi_rwlock_t bufCreateLock; /* read-locked during buffer creation;
- * write-locked to prevent buffers from
- * being created during a truncate op, etc.
- */
- int refCount; /* reference count; cm_scacheLock */
- osi_queueData_t *bufReadsp; /* queue of buffers being read */
- osi_queueData_t *bufWritesp; /* queue of buffers being written */
-
- /* parent info for ACLs */
- long parentVnode; /* parent vnode for ACL callbacks */
- long parentUnique; /* for ACL callbacks */
-
- /* local modification stat */
- long mask; /* for clientModTime, length and
- * truncPos */
-
- /* file status */
- int fileType; /* file type */
- unsigned long clientModTime; /* mtime */
- unsigned long serverModTime; /* at server, for concurrent call
- * comparisons */
- osi_hyper_t length; /* file length */
- cm_prefetch_t prefetch; /* prefetch info structure */
- int unixModeBits; /* unix protection mode bits */
- int linkCount; /* link count */
- long dataVersion; /* data version */
- long owner; /* file owner */
- long group; /* file owning group */
-
- /* pseudo file status */
- osi_hyper_t serverLength; /* length known to server */
-
- /* aux file status */
- osi_hyper_t truncPos; /* file size to truncate to before
- * storing data */
-
- /* symlink and mount point info */
- char *mountPointStringp; /* the string stored in a mount point;
- * first char is type, then vol name.
+ osi_queue_t q; /* lru queue; cm_scacheLock */
+ afs_uint32 magic;
+ struct cm_scache *nextp; /* next in hash; cm_scacheLock */
+ cm_fid_t fid;
+ afs_uint32 flags; /* flags; locked by mx */
+
+ /* synchronization stuff */
+ osi_mutex_t mx; /* mutex for this structure */
+ osi_rwlock_t bufCreateLock; /* read-locked during buffer creation;
+ * write-locked to prevent buffers from
+ * being created during a truncate op, etc.
+ */
+ afs_uint32 refCount; /* reference count; cm_scacheLock */
+ osi_queueData_t *bufReadsp; /* queue of buffers being read */
+ osi_queueData_t *bufWritesp; /* queue of buffers being written */
+
+ /* parent info for ACLs */
+ afs_uint32 parentVnode; /* parent vnode for ACL callbacks */
+ afs_uint32 parentUnique; /* for ACL callbacks */
+
+ /* local modification stat */
+ afs_uint32 mask; /* for clientModTime, length and
+ * truncPos */
+
+ /* file status */
+ afs_uint32 fileType; /* file type */
+ time_t clientModTime; /* mtime */
+ time_t serverModTime; /* at server, for concurrent call
+ * comparisons */
+ osi_hyper_t length; /* file length */
+ cm_prefetch_t prefetch; /* prefetch info structure */
+ afs_uint32 unixModeBits; /* unix protection mode bits */
+ afs_uint32 linkCount; /* link count */
+ afs_uint32 dataVersion; /* data version */
+ afs_uint32 owner; /* file owner */
+ afs_uint32 group; /* file owning group */
+ cm_user_t *creator; /* user, if new file */
+
+ /* pseudo file status */
+ osi_hyper_t serverLength; /* length known to server */
+
+ /* aux file status */
+ osi_hyper_t truncPos; /* file size to truncate to before
+ * storing data */
+
+ /* symlink and mount point info */
+ char mountPointStringp[MOUNTPOINTLEN]; /* the string stored in a mount point;
+ * first char is type, then vol name.
* If this is a normal symlink, we store
* the link contents here.
*/
- cm_fid_t *mountRootFidp; /* mounted on root */
- unsigned int mountRootGen; /* time to update mountRootFidp? */
- cm_fid_t *dotdotFidp; /* parent of volume root */
+ cm_fid_t mountRootFid; /* mounted on root */
+ time_t mountRootGen; /* time to update mountRootFidp? */
+ cm_fid_t dotdotFid; /* parent of volume root */
+
+ /* callback info */
+ struct cm_server *cbServerp; /* server granting callback */
+ time_t cbExpires; /* time callback expires */
+
+ /* access cache */
+ long anyAccess; /* anonymous user's access */
+ struct cm_aclent *randomACLp; /* access cache entries */
+
+ /* file locks */
+ afs_int32 serverLock; /* current lock we have acquired on
+ * this file. One of (-1), LockRead
+ * or LockWrite. [protected by
+ * scp->mx]. In the future, this
+ * should be replaced by a queue of
+ * cm_server_lock_t objects which keep
+ * track of lock type, the user for
+ * whom the lock was obtained, the
+ * dataVersion at the time the lock
+ * was asserted last, lastRefreshCycle
+ * and lateUpdateTime.
+ */
+ unsigned long lastRefreshCycle; /* protected with cm_scacheLock
+ * for all scaches. */
+ afs_uint32 lockDataVersion; /* dataVersion of the scp at the time
+ the server lock for the scp was
+ asserted for this lock the last
+ time. */
+ osi_queue_t *fileLocksH; /* queue of locks (head) */
+ osi_queue_t *fileLocksT; /* queue of locks (tail) */
+
+ afs_uint32 sharedLocks; /* number of shared locks on
+ * ::fileLocks. This count does not
+ * include locks which have
+ * CM_FILELOCK_FLAG_CLIENTONLY set. */
+
+ afs_uint32 exclusiveLocks; /* number of exclusive locks on
+ * ::fileLocks. This count does not
+ * include locks which have
+ * CM_FILELOCK_FLAG_CLIENTONLY set.
+ */
+
+ afs_uint32 clientLocks; /* number of locks on ::fileLocks that
+ have CM_FILELOCK_FLAG_CLIENTONLY
+ set. */
+
+ /* volume info */
+ struct cm_volume *volp; /* volume info; held reference */
- /* callback info */
- struct cm_server *cbServerp; /* server granting callback */
- long cbExpires; /* time callback expires */
+ /* bulk stat progress */
+ osi_hyper_t bulkStatProgress; /* track bulk stats of large dirs */
- /* access cache */
- long anyAccess; /* anonymous user's access */
- struct cm_aclent *randomACLp; /* access cache entries */
+ /* open state */
+ afs_uint16 openReads; /* open for reading */
+ afs_uint16 openWrites; /* open for writing */
+ afs_uint16 openShares; /* open for read excl */
+ afs_uint16 openExcls; /* open for exclusives */
- /* file locks */
- osi_queue_t *fileLocks;
-
- /* volume info */
- struct cm_volume *volp; /* volume info; held reference */
-
- /* bulk stat progress */
- osi_hyper_t bulkStatProgress; /* track bulk stats of large dirs */
-
- /* open state */
- short openReads; /* opens for reading */
- short openWrites; /* open for writing */
- short openShares; /* open for read excl */
- short openExcls; /* open for exclusives */
+ /* syncop state */
+ afs_uint32 waitCount; /* number of threads waiting */
+ afs_uint32 waitRequests; /* num of thread wait requests */
} cm_scache_t;
/* mask field - tell what has been modified */
#define CM_SCACHETYPE_DIRECTORY 2 /* a dir */
#define CM_SCACHETYPE_SYMLINK 3 /* a symbolic link */
#define CM_SCACHETYPE_MOUNTPOINT 4 /* a mount point */
+#define CM_SCACHETYPE_DFSLINK 5 /* a Microsoft Dfs link */
+#define CM_SCACHETYPE_INVALID 99 /* an invalid link */
/* flag bits */
-#define CM_SCACHEFLAG_STATD 1 /* status info is valid */
-#define CM_SCACHEFLAG_DELETED 2 /* file has been deleted */
-#define CM_SCACHEFLAG_CALLBACK 4 /* have a valid callback */
-#define CM_SCACHEFLAG_STORING 8 /* status being stored back */
+#define CM_SCACHEFLAG_STATD 0x01 /* status info is valid */
+#define CM_SCACHEFLAG_DELETED 0x02 /* file has been deleted */
+#define CM_SCACHEFLAG_CALLBACK 0x04 /* have a valid callback */
+#define CM_SCACHEFLAG_STORING 0x08 /* status being stored back */
#define CM_SCACHEFLAG_FETCHING 0x10 /* status being fetched */
#define CM_SCACHEFLAG_SIZESTORING 0x20 /* status being stored that
* changes the data; typically,
#define CM_SCACHEFLAG_ANYWATCH \
(CM_SCACHEFLAG_WATCHED | CM_SCACHEFLAG_WATCHEDSUBTREE)
+#define CM_SCACHEFLAG_EACCESS 0x200000 /* Bulk Stat returned EACCES */
+#define CM_SCACHEFLAG_SMB_FID 0x400000
+
/* sync flags for calls to the server. The CM_SCACHEFLAG_FETCHING,
* CM_SCACHEFLAG_STORING and CM_SCACHEFLAG_SIZESTORING flags correspond to the
* below, except for FETCHDATA and STOREDATA, which correspond to non-null
* These flags correspond to individual RPCs that we may be making, and at most
* one can be set in any one call to SyncOp.
*/
-#define CM_SCACHESYNC_FETCHSTATUS 1 /* fetching status info */
-#define CM_SCACHESYNC_STORESTATUS 2 /* storing status info */
-#define CM_SCACHESYNC_FETCHDATA 4 /* fetch data */
-#define CM_SCACHESYNC_STOREDATA 8 /* store data */
+#define CM_SCACHESYNC_FETCHSTATUS 0x01 /* fetching status info */
+#define CM_SCACHESYNC_STORESTATUS 0x02 /* storing status info */
+#define CM_SCACHESYNC_FETCHDATA 0x04 /* fetch data */
+#define CM_SCACHESYNC_STOREDATA 0x08 /* store data */
#define CM_SCACHESYNC_STORESIZE 0x10 /* store new file size */
#define CM_SCACHESYNC_GETCALLBACK 0x20 /* fetching a callback */
#define CM_SCACHESYNC_STOREDATA_EXCL 0x40 /* store data */
#define CM_SCACHESYNC_BUFLOCKED 0x80000 /* the buffer is locked */
#define CM_SCACHESYNC_NOWAIT 0x100000/* don't wait for the state,
* just fail */
+#define CM_SCACHESYNC_FORCECB 0x200000/* when calling cm_GetCallback()
+ * set the force flag */
+
+/* flags for cm_RecycleSCache */
+#define CM_SCACHE_RECYCLEFLAG_DESTROY_BUFFERS 0x1
/* flags for cm_MergeStatus */
#define CM_MERGEFLAG_FORCE 1 /* check mtime before merging;
((fidp)->volume + \
(fidp)->vnode + \
(fidp)->unique)) \
- % cm_hashTableSize)
+ % cm_data.hashTableSize)
-extern cm_scache_t cm_fakeSCache;
+#include "cm_conn.h"
+#include "cm_buf.h"
-extern void cm_InitSCache(long);
+extern void cm_InitSCache(int, long);
extern long cm_GetSCache(cm_fid_t *, cm_scache_t **, struct cm_user *,
struct cm_req *);
extern int cm_FidCmp(cm_fid_t *, cm_fid_t *);
extern long cm_SyncOp(cm_scache_t *, struct cm_buf *, struct cm_user *,
- struct cm_req *, long, long);
+ struct cm_req *, afs_uint32, afs_uint32);
-extern void cm_SyncOpDone(cm_scache_t *, struct cm_buf *, long);
+extern void cm_SyncOpDone(cm_scache_t *, struct cm_buf *, afs_uint32);
extern void cm_MergeStatus(cm_scache_t *, struct AFSFetchStatus *, struct AFSVolSync *,
- struct cm_user *, int flags);
+ struct cm_user *, afs_uint32 flags);
extern void cm_AFSFidFromFid(struct AFSFid *, cm_fid_t *);
+#ifdef DEBUG_REFCOUNT
+extern void cm_HoldSCacheNoLockDbg(cm_scache_t *, char *, long);
+
+extern void cm_HoldSCacheDbg(cm_scache_t *, char *, long);
+
+extern void cm_ReleaseSCacheNoLockDbg(cm_scache_t *, char *, long);
+
+extern void cm_ReleaseSCacheDbg(cm_scache_t *, char *, long);
+
+#define cm_HoldSCacheNoLock(scp) cm_HoldSCacheNoLockDbg(scp, __FILE__, __LINE__)
+#define cm_HoldSCache(scp) cm_HoldSCacheDbg(scp, __FILE__, __LINE__)
+#define cm_ReleaseSCacheNoLock(scp) cm_ReleaseSCacheNoLockDbg(scp, __FILE__, __LINE__)
+#define cm_ReleaseSCache(scp) cm_ReleaseSCacheDbg(scp, __FILE__, __LINE__)
+#else
+extern void cm_HoldSCacheNoLock(cm_scache_t *);
+
extern void cm_HoldSCache(cm_scache_t *);
-extern void cm_ReleaseSCache(cm_scache_t *);
+extern void cm_ReleaseSCacheNoLock(cm_scache_t *);
+extern void cm_ReleaseSCache(cm_scache_t *);
+#endif
extern cm_scache_t *cm_FindSCache(cm_fid_t *fidp);
-extern long cm_hashTableSize;
+extern cm_scache_t *cm_FindSCacheParent(cm_scache_t *);
extern osi_rwlock_t cm_scacheLock;
extern osi_queue_t *cm_allFileLocks;
-extern cm_scache_t **cm_hashTablep;
+extern osi_queue_t *cm_freeFileLocks;
+
+extern unsigned long cm_lockRefreshCycle;
extern void cm_DiscardSCache(cm_scache_t *scp);
+extern int cm_FindFileType(cm_fid_t *fidp);
+
+extern long cm_ValidateSCache(void);
+
+extern long cm_ShutdownSCache(void);
+
+extern long cm_RecycleSCache(cm_scache_t *scp, afs_int32 flags);
+
+extern void cm_RemoveSCacheFromHashTable(cm_scache_t *scp);
#endif /* __CM_SCACHE_H_ENV__ */