/* $Header: /afs/transarc.com/project/fs/dev/afs/rcs/vol/RCS/volume.h,v 2.7 1993/08/30 16:38:31 vasilis Exp $ */
/* $Source: /afs/transarc.com/project/fs/dev/afs/rcs/vol/RCS/volume.h,v $ */

#ifndef __volume_h
#define	__volume_h  1

#if !defined(lint) && !defined(LOCORE) && defined(RCS_HDRS)
static char *rcsidvolume = "$Header: /afs/transarc.com/project/fs/dev/afs/rcs/vol/RCS/volume.h,v 2.7 1993/08/30 16:38:31 vasilis Exp $";
#endif

/*
 * P_R_P_Q_# (C) COPYRIGHT IBM CORPORATION 1987
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/*

	System:		VICE-TWO
	Module:		volume.h
	Institution:	The Information Technology Center, Carnegie-Mellon University

 */

#include "voldefs.h"
#define VolumeWriteable(vp)		(V_type(vp)==readwriteVolume)
#define VolumeWriteable2(vol)		(vol.type == readwriteVolume)
typedef bit32				FileOffset; /* Offset in this file */

typedef enum {fileServer, volumeUtility, salvager} ProgramType;
ProgramType programType;	/* The type of program using the package */

/* Some initialization parameters for the volume package */
/* Add new initialization parameters here */
int (*V_BreakVolumeCallbacks)();
extern int (*vol_PollProc)();
#define	DOPOLL	((vol_PollProc)? (*vol_PollProc)() : 0)

struct versionStamp {		/* Version stamp for critical volume files */
    bit32	magic;		/* Magic number */
    bit32	version;	/* Version number of this file, or software
    				   that created this file */
};

/* Magic numbers and version stamps for each type of file */
#define VOLUMEHEADERMAGIC	0x88a1bb3c
#define VOLUMEINFOMAGIC		0x78a1b2c5
#define	SMALLINDEXMAGIC		0x99776655
#define LARGEINDEXMAGIC		0x88664433
#define	MOUNTMAGIC		0x9a8b7c6d
#define ACLMAGIC		0x88877712

#define VOLUMEHEADERVERSION	1
#define VOLUMEINFOVERSION	1
#define	SMALLINDEXVERSION	1
#define	LARGEINDEXVERSION	1
#define	MOUNTVERSION		1
#define ACLVERSION		1

/*
 * Define whether we are keeping detailed statistics on volume dealings.
 */
#define TRANSARC_VOL_STATS	1

#if TRANSARC_VOL_STATS
/*
 * Define various indices and counts used in keeping volume-level statistics.
 */
#define VOL_STATS_NUM_RWINFO_FIELDS 4

#define VOL_STATS_SAME_NET	0	/*Within same site (total)*/
#define VOL_STATS_SAME_NET_AUTH 1	/*Within same site (authenticated);
					  (must be 1 more than above)*/
#define VOL_STATS_DIFF_NET	2	/*From external site (total)*/
#define VOL_STATS_DIFF_NET_AUTH 3	/*From external site (authenticated)
					  (must be 1 more than above)*/

#define VOL_STATS_NUM_TIME_RANGES 6

#define VOL_STATS_TIME_CAP_0	    60	/*60 seconds*/
#define VOL_STATS_TIME_CAP_1	   600	/*10 minutes, in seconds*/
#define VOL_STATS_TIME_CAP_2	  3600	/*1 hour, in seconds*/
#define VOL_STATS_TIME_CAP_3	 86400	/*1 day, in seconds*/
#define VOL_STATS_TIME_CAP_4	604800	/*1 week, in seconds*/

#define VOL_STATS_NUM_TIME_FIELDS 6

#define VOL_STATS_TIME_IDX_0	0	/*0 secs to 60 secs*/
#define VOL_STATS_TIME_IDX_1	1	/*1 min to 10 mins*/
#define VOL_STATS_TIME_IDX_2	2	/*10 mins to 60 mins*/
#define VOL_STATS_TIME_IDX_3	3	/*1 hr to 24 hrs*/
#define VOL_STATS_TIME_IDX_4	4	/*1 day to 7 days*/
#define VOL_STATS_TIME_IDX_5	5	/*Greater than 1 week*/
#endif /* TRANSARC_VOL_STATS */

/* Volume header.  This is the contents of the named file representing
   the volume.  Read-only by the file server! */
struct VolumeHeader {
    struct versionStamp	stamp;/* Must be first field */
    VolumeId	id;	      /* Volume number */
    VolumeId	parent;	      /* Read-write volume number (or this volume
    				 number if this is a read-write volume) */
    Inode	volumeInfo;
    Inode	smallVnodeIndex;
    Inode	largeVnodeIndex;
    Inode	volumeAcl;
    Inode	volumeMountTable;
    bit32	reserved[10];	/* If you add fields, add them before
    				   here and reduce the size of this array */
};

/* A vnode index file header */
struct IndexFileHeader {
    struct versionStamp stamp;
};


/******************************************************************************/
/* Volume Data which is stored on disk and can also be maintained in memory.  */
/******************************************************************************/
typedef struct VolumeDiskData {
    struct versionStamp stamp;	/* Must be first field */
    VolumeId	id;		/* Volume id--unique over all systems */
#define VNAMESIZE 32		/* including 0 byte */
    char	name[VNAMESIZE];/* Unofficial name for the volume */
    byte	inUse;		/* Volume is being used (perhaps it is online),
    				   or the system crashed while it was used */
    byte	inService;	/* Volume in service, not necessarily on line
    				   This bit is set by an operator/system
				   programmer.  Manually taking a volume offline
				   always clears the inService bit. Taking
				   it out of service also takes it offline */
    byte	blessed;	/* Volume is administratively blessed with
    				   the ability to go on line.  Set by a system
				   administrator. Clearing this bit will
				   take the volume offline */
    byte	needsSalvaged;	/* Volume needs salvaged--an unrecoverable
    				   error occured to the volume.  Note:  a volume
				   may still require salvage even if this
				   flag isn't set--e.g. if a system crash
				   occurred while the volume was on line. */
    bit32	uniquifier;	/* Next vnode uniquifier for this volume */
    int		type;		/* */
    VolId	parentId;	/* Id of parent, if type==readonly */
    VolId	cloneId;	/* Latest read-only clone, if type==readwrite,
    				   0 if the volume has never been cloned.  Note: the
				   indicated volume does not necessarily exist (it
				   may have been deleted since cloning). */
    VolId	backupId;	/* Latest backup copy of this read write volume */
    VolId	restoredFromId; /* The id in the dump this volume was restored from--used simply
    				   to make sure that an incremental dump is not restored on top
				   of something inappropriate:  Note:  this field itself is NEVER
				   dumped!!! */
    byte	needsCallback;	/* Set by the salvager if anything was changed
    				   about the volume.  Note:  this is not set by
				   clone/makebackups when setting the copy-on-write
				   flag in directories; this flag is not seen by
				   the clients. */
#define DESTROY_ME	0xD3
    byte	destroyMe;	/* If this is set to DESTROY_ME, then the salvager should destroy
				   this volume; it is bogus (left over from an aborted  volume move,
				   for example).  Note:  if this flag is on, then inService should
				   be OFF--only the salvager checks this flag */
#define DONT_SALVAGE	0xE5
    byte	dontSalvage;	/* If this is on, then don't bother salvaging this volume*/
    byte	reserveb3;

    bit32	reserved1[6];


    /* Administrative stuff */
    int		maxquota;	/* Quota maximum, 1K blocks */
    int		minquota;	/* Quota minimum, 1K blocks */
    int		maxfiles;	/* Maximum number of files (i.e. inodes) */
    bit32	accountNumber;  /* Uninterpreted account number */
    bit32	owner;		/* The person administratively responsible
				   for this volume */
    int		reserved2[8];	/* Other administrative constraints */

    /* Resource usage & statistics */
    int		filecount;	/* Actual number of files */
    int		diskused;	/* Actual disk space used, 1K blocks */
    int		dayUse;		/* Metric for today's usage of this volume so far */
    int		weekUse[7];	/* Usage of the volume for the last week.
				   weekUse[0] is for most recent complete 24 hour period
				   of measurement; week[6] is 7 days ago */
    Date	dayUseDate;	/* Date the dayUse statistics refer to; the week use stats
				   are the preceding 7 days */
    int		reserved3[11];	/* Other stats here */
    
    /* Server supplied dates */
    Date	creationDate;   /* Creation date for a read/write
    				   volume; cloning date for original copy of
				   a readonly volume (replicated volumes have
				   the same creation date) */
    Date	accessDate;	/* Last access time by a user, large granularity */
    Date	updateDate;	/* Last modification by user */
    Date	expirationDate; /* 0 if it never expires */
    Date	backupDate;	/* last time a backup clone was taken */

    /* Time that this copy of this volume was made.  NEVER backed up.  This field is only
       set when the copy is created */
    Date	copyDate;

#if TRANSARC_VOL_STATS
    bit32	stat_initialized;  /*Are the stat fields below set up?*/
    bit32	reserved4[7];
#else
    bit32	reserved4[8];
#endif /* TRANSARC_VOL_STATS */

    /* messages */
#define VMSGSIZE 128
    char	offlineMessage[VMSGSIZE]; /* Why the volume is offline */
#if TRANSARC_VOL_STATS
#define VOL_STATS_BYTES 128
   /*
    * Keep per-volume aggregate statistics on type and distance of access,
    * along with authorship info.
    */
   bit32	stat_reads[VOL_STATS_NUM_RWINFO_FIELDS];
   bit32	stat_writes[VOL_STATS_NUM_RWINFO_FIELDS];
   bit32	stat_fileSameAuthor[VOL_STATS_NUM_TIME_FIELDS];
   bit32	stat_fileDiffAuthor[VOL_STATS_NUM_TIME_FIELDS];
   bit32	stat_dirSameAuthor[VOL_STATS_NUM_TIME_FIELDS];
   bit32	stat_dirDiffAuthor[VOL_STATS_NUM_TIME_FIELDS];
#else
    char 	motd[VMSGSIZE];	 	  /* Volume "message of the day" */
#endif /* TRANSARC_VOL_STATS */

} VolumeDiskData;


/**************************************/
/* Memory resident volume information */
/**************************************/
typedef struct Volume {
    struct	Volume 	*hashNext; /* Next in hash resolution table */
    VolumeId	hashid;		/* Volume number -- for hash table lookup */
    struct	volHeader *header; /* Cached disk data */
    Device	device;		/* Unix device for the volume */ 
    struct DiskPartition
    		*partition;	/* Information about the Unix partition */
    struct vnodeIndex {
      Inode	inode;		/* Unix inode holding this index */
      byte      *bitmap;	/* Index bitmap */
      unsigned long	bitmapSize;	/* length of bitmap, in bytes */
      unsigned long	bitmapOffset;	/* Which byte address of the first long to
				   start search from in bitmap */
    } vnodeIndex[nVNODECLASSES];
    Unique	nextVnodeUnique;/* Derived originally from volume uniquifier.
			   	   This is the actual next version number to
			   	   assign; the uniquifier is bumped by 50 and
			   	   and written to disk every 50 file creates
			   	   If the volume is shutdown gracefully, the
				   uniquifier should be rewritten with the
				   value nextVnodeVersion*/
    Inode	diskDataInode;	/* Unix inode holding general volume info */
    bit16	vnodeHashOffset;/* Computed by HashOffset function in vnode.h.
				   Assigned to the volume when initialized. 
				   Added to vnode number for hash table index */
    byte	shuttingDown;	/* This volume is going to be detached */
    byte	goingOffline;	/* This volume is going offline */
    bit16	cacheCheck;	/* Online sequence number to be used to invalidate vnode cache entries
    				   that stayed around while a volume was offline */
    short	nUsers;		/* Number of users of this volume header */
    byte	needsPutBack;	/* For a volume utility, this flag is set if we need
				   to give the volume back when we detach it.  The server has
				   certain modes where it doesn't detach the volume, and
				   if we give it back spuriously, the server aborts.  This field
				   is meaningless on the file server */
    byte	specialStatus;	/* An error code to return on VGetVolume: the
				   volume is unavailable for the reason quoted,
				   currently VBUSY or VMOVED */
    long	updateTime;	/* Time that this volume was put on the updated
				   volume list--the list of volumes that will be
				   salvaged should the file server crash */
} Volume;

struct volHeader {
    struct volHeader *prev, *next;/* LRU pointers */
    VolumeDiskData diskstuff;	/* General volume info read from disk */
    Volume *back;		/* back pointer to current volume structure */
};

/* These macros are used to export fields within the volume header.  This was added
   to facilitate changing the actual representation */

#define V_device(vp)		((vp)->device)
#define V_partition(vp)		((vp)->partition)
#define V_inode(vp)		((vp)->inode)
#define V_diskDataInode(vp)	((vp)->diskDataInode)
#define V_vnodeIndex(vp)	((vp)->vnodeIndex)
#define V_nextVnodeUnique(vp)	((vp)->nextVnodeUnique)

/* N.B. V_id must be this, rather than vp->id, or some programs will break, probably */
#define V_stamp(vp)		((vp)->header->diskstuff.stamp)
#define V_id(vp)		((vp)->header->diskstuff.id)
#define V_name(vp)		((vp)->header->diskstuff.name)
#define V_inUse(vp)		((vp)->header->diskstuff.inUse)
#define V_inService(vp)		((vp)->header->diskstuff.inService)
#define V_blessed(vp)		((vp)->header->diskstuff.blessed)
#define V_needsSalvaged(vp)	((vp)->header->diskstuff.needsSalvaged)
#define V_uniquifier(vp)	((vp)->header->diskstuff.uniquifier)
#define V_type(vp)		((vp)->header->diskstuff.type)
#define V_parentId(vp)		((vp)->header->diskstuff.parentId)
#define V_cloneId(vp)		((vp)->header->diskstuff.cloneId)
#define V_backupId(vp)		((vp)->header->diskstuff.backupId)
#define V_restoredFromId(vp)	((vp)->header->diskstuff.restoredFromId)
#define V_needsCallback(vp)	((vp)->header->diskstuff.needsCallback)
#define V_destroyMe(vp)		((vp)->header->diskstuff.destroyMe)
#define V_dontSalvage(vp)	((vp)->header->diskstuff.dontSalvage)
#define V_maxquota(vp)		((vp)->header->diskstuff.maxquota)
#define V_minquota(vp)		((vp)->header->diskstuff.minquota)
#define V_maxfiles(vp)		((vp)->header->diskstuff.maxfiles)
#define V_accountNumber(vp)	((vp)->header->diskstuff.accountNumber)
#define V_owner(vp)		((vp)->header->diskstuff.owner)
#define V_filecount(vp)		((vp)->header->diskstuff.filecount)
#define V_diskused(vp)		((vp)->header->diskstuff.diskused)
#define V_dayUse(vp)		((vp)->header->diskstuff.dayUse)
#define V_weekUse(vp)		((vp)->header->diskstuff.weekUse)
#define V_dayUseDate(vp)	((vp)->header->diskstuff.dayUseDate)
#define V_creationDate(vp)	((vp)->header->diskstuff.creationDate)
#define V_accessDate(vp)	((vp)->header->diskstuff.accessDate)
#define V_updateDate(vp)	((vp)->header->diskstuff.updateDate)
#define V_expirationDate(vp)	((vp)->header->diskstuff.expirationDate)
#define V_backupDate(vp)	((vp)->header->diskstuff.backupDate)
#define V_copyDate(vp)		((vp)->header->diskstuff.copyDate)
#define V_offlineMessage(vp)	((vp)->header->diskstuff.offlineMessage)
#define V_disk(vp)		((vp)->header->diskstuff)
#if TRANSARC_VOL_STATS
#define V_stat_initialized(vp)	((vp)->header->diskstuff.stat_initialized)
#define V_stat_area(vp)		(((vp)->header->diskstuff.stat_reads))
#define V_stat_reads(vp, idx)	(((vp)->header->diskstuff.stat_reads)[idx])
#define V_stat_writes(vp, idx)	(((vp)->header->diskstuff.stat_writes)[idx])
#define V_stat_fileSameAuthor(vp, idx) (((vp)->header->diskstuff.stat_fileSameAuthor)[idx])
#define V_stat_fileDiffAuthor(vp, idx) (((vp)->header->diskstuff.stat_fileDiffAuthor)[idx])
#define V_stat_dirSameAuthor(vp, idx)  (((vp)->header->diskstuff.stat_dirSameAuthor)[idx])
#define V_stat_dirDiffAuthor(vp, idx)  (((vp)->header->diskstuff.stat_dirDiffAuthor)[idx])
#else
#define V_motd(vp)		((vp)->header->diskstuff.motd)
#endif /* TRANSARC_VOL_STATS */

/* File offset computations.  The offset values in the volume header are
   computed with these macros -- when the file is written only!! */
#define VOLUME_MOUNT_TABLE_OFFSET(Volume)	(sizeof (VolumeDiskData))
#define VOLUME_BITMAP_OFFSET(Volume)	\
	(sizeof (VolumeDiskData) + (Volume)->disk.mountTableSize)


extern char *VSalvageMessage;	/* Canonical message when a volume is forced
				   offline */
extern Volume * VGetVolume();
extern Volume * VAttachVolume();
extern Volume * VCreateVolume();
extern VnodeId VallocBitMapEntry();
extern VFreeBitMapEntry();
extern int VolumeNumber();
extern char * VolumeExternalName();
extern Volume * VAttachVolumeByName();

/* Naive formula relating number of file size to number of 1K blocks in file */
/* Note:  we charge 1 block for 0 length files so the user can't store
   an inifite number of them; for most files, we give him the inode, vnode,
   and indirect block overhead, for FREE! */
#define nBlocks(bytes) ((bytes) == 0? 1: ((bytes)+1023)/1024)

/* Client process id -- file server sends a Check volumes signal back to the client at this pid */
#define CLIENTPID	"/vice/vol/clientpid"

/* Modes of attachment, for VAttachVolume[ByName] to convey to the file server */
#define	V_READONLY 1	/* Absolutely no updates will be done to the volume */
#define V_CLONE	   2	/* Cloning the volume:  if it is read/write, then directory
			   version numbers will change.  Header will be updated.  If
			   the volume is read-only, the file server may continue to
			   server it; it may also continue to server it in read/write
			   mode if the writes are deferred */
#define V_UPDATE   3	/* General update or volume purge is possible.  Volume must
			   go offline */
#define V_DUMP	   4	/* A dump of the volume is requested; the volume can be served
			   read-only during this time */
#define V_SECRETLY 5	/* Secret attach of the volume.  This is used to attach a volume
			   which the file server doesn't know about--and which it shouldn't
			   know about yet, since the volume has just been created and
			   is somewhat bogus.  Required to make sure that a file server
			   never knows about more than one copy of the same volume--when
			   a volume is moved from one partition to another on a single
			   server */

#endif /* __volume_h */
