/* BLURB gpl

                           Coda File System
                              Release 8

          Copyright (c) 1987-2021 Carnegie Mellon University
                  Additional copyrights listed below

This  code  is  distributed "AS IS" without warranty of any kind under
the terms of the GNU General Public Licence Version 2, as shown in the
file  LICENSE.  The  technical and financial  contributors to Coda are
listed in the file CREDITS.

                        Additional copyrights

#*/

/*
                         IBM COPYRIGHT NOTICE

                          Copyright (C) 1986
             International Business Machines Corporation
                         All Rights Reserved

This  file  contains  some  code identical to or derived from the 1986
version of the Andrew File System ("AFS"), which is owned by  the  IBM
Corporation.   This  code is provided "AS IS" and IBM does not warrant
that it is free of infringement of  any  intellectual  rights  of  any
third  party.    IBM  disclaims  liability of any kind for any damages
whatsoever resulting directly or indirectly from use of this  software
or  of  any  derivative work.  Carnegie Mellon University has obtained
permission to  modify,  distribute and sublicense this code,  which is
based on Version 2  of  AFS  and  does  not  contain  the features and
enhancements that are part of  Version 3 of  AFS.  Version 3 of AFS is
commercially   available   and  supported  by   Transarc  Corporation,
Pittsburgh, PA.

*/

#ifndef VOLUME_INCLUDED
#define VOLUME_INCLUDED 1

#include <recov_vollog.h>
#include <vice.h>
#include <dllist.h>
#include <partition.h>
#include "voldefs.h"

#define VolumeWriteable(vp) \
    (V_type(vp) == readwriteVolume || V_type(vp) == nonReplicatedVolume)

#define FSTAG 84597 /* Unique tag for fileserver lwp rocks */

/* volume flags indicating which type of resolution is turned on */
//#define VMRES	1
#define RVMRES 4

typedef bit32 FileOffset; /* Offset in this file */
typedef enum
{
    fileServer,
    volumeUtility,
    salvager,
    fsUtility
} ProgramType;

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 MAXVOLS_PER_PARTITION 1000 /* Max number of volumes per partition */

/* Volume header.  This used to be the contents of the named file representing
   the volume; now stored in recoverable storage.  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 if readwrite) */
    int type; /* volume type: RWVOL, ROVOL, BACKVOL */
};

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

/*
VolumeDiskData:Volume administrative data stored in RVM.
*/

typedef struct VolumeDiskData {
    struct versionStamp stamp; /* Must be first field */
    VolumeId id; /* Volume id--unique over all systems */
    /* filesystem partition on which volume data resides, and unofficial name
     * for the volume */
    char partition[V_MAXPARTNAMELEN];
    char name[V_MAXVOLNAMELEN];
    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
                           occurred 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; /* RWVOL, ROVOL, BACKVOL */
    VolumeId parentId; /* Id of parent, if type==readonly */
    VolumeId groupId; /* Id of replication group, or 0 if not replicated */
    VolumeId 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). */
    VolumeId backupId; /* Latest backup copy of this read write volume */
    VolumeId 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;

    ViceVersionVector versionvector; /* Coda version vector for this volume */
    int ResOn; /* Flag to turn on resolution */
    bit32 reserved1[5];

    /* 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 */
    bit16 linkcount; /* number of links */
    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_t 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_t creationDate; /* Creation date for a read/write volume; cloning date
                            for original copy of a readonly volume (readonly
                            replicas volumes have the same creation date) */
    Date_t accessDate; /* Last access time by a user, large granularity */
    Date_t updateDate; /* Last modification by user */
    Date_t expirationDate; /* 0 if it never expires */
    Date_t 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_t copyDate;
    recov_vol_log *log; /* Recoverable resolution log for this volume */
    bit32 reserved4[7];

    /* messages */
#define VMSGSIZE 128
    char offlineMessage[VMSGSIZE]; /* Why the volume is offline */
    char motd[VMSGSIZE]; /* Volume "message of the day" */

    char pad[4]; /* make size multiple of 4 */

} VolumeDiskData;

/* Debugging routine (Satya, May 2004) (vol-debug.c) */
void PrintVolumeDiskData(FILE *, VolumeDiskData *);

/**************************************/
/* Memory resident volume information */
/**************************************/

/*
VM bitmap that shows which vnodes are allocated
 */
struct vnodeIndex {
    byte *bitmap; /* Index bitmap */
    unsigned short bitmapSize; /* length of bitmap, in bytes */
    unsigned short bitmapOffset; /* Which byte address of the
					   first long to start search
					   from in bitmap */
};

/*
 */
struct VolLock {
    struct Lock VolumeLock; /* Prevent mutations during backup/clone */
    unsigned IPAddress;
};

/* VM structure maintained per volume */
struct Volume {
    struct Volume *hashNext; /* Next in hash resolution table */
    VolumeId hashid; /* Volume number -- for hash table lookup */
    struct volHeader *header; /* Cached disk data */
    struct DiskPartition *partition; /* Information about the Unix partition */
    int vol_index; /* index of this volume in recoverable volume array */
    struct vnodeIndex vnIndex[nVNODECLASSES];
    Unique_t 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*/
    bit16 vnodeHashOffset; /* Computed by HashOffset function in cvnode.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 */
    int32_t specialStatus; /* An error code to return on VGetVolume: the
                              volume is unavailable for the reason quoted,
                              currently VBUSY or VMOVED */
    int32_t 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 */
    struct Lock lock; /* internal lock */
    PROCESS writer; /* process id having write lock */
    struct VolLock VolLock; /* Volume level lock for backup/clone */
#define VNREINTEGRATORS 8 /* List size increment */
    int nReintegrators; /* Number of clients that have successfully
                           reintegrated with this volume. */
    ViceStoreId *reintegrators; /* List of identifiers representing the last
				   record reintegrated for each client. Could
				   be moved to recoverable store if necessary.
				*/
};
typedef struct Volume Volume;

/*
  Cached version of the volume's administrative data
*/
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_partition(vp) ((vp)->partition)
#define V_device(vp) (V_partition(vp)->device)
#define V_inode(vp) ((vp)->inode)
/*#define V_diskDataInode(vp)	((vp)->diskDataInode) */
#define V_vnodeIndex(vp) ((vp)->vnIndex)
#define V_nextVnodeUnique(vp) ((vp)->nextVnodeUnique)
#define V_volumeindex(vp) ((vp)->vol_index)
#define V_lock(vp) ((vp)->lock)
#define V_writer(vp) ((vp)->writer)
#define V_VolLock(vp) (((vp)->VolLock))

/* 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_partname(vp) ((vp)->header->diskstuff.partition)
#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_groupId(vp) ((vp)->header->diskstuff.groupId)
#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_versionvector(vp) ((vp)->header->diskstuff.versionvector)
#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_linkcount(vp) ((vp)->header->diskstuff.linkcount)
#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_motd(vp) ((vp)->header->diskstuff.motd)
#define V_disk(vp) ((vp)->header->diskstuff)
#define V_RVMResOn(vp) ((vp)->header->diskstuff.ResOn & RVMRES)
#define V_VolLog(vp) ((vp)->header->diskstuff.log)

extern char *ThisHost; /* This machine's hostname */
extern uint8_t ThisServerId; /* this server id, as found in
				   /vice/db/servers */
extern bit32 HostAddress[]; /* Assume host addresses are 32 bits */
extern int VInit; /* Set to 1 when the volume package is
				   initialized */
extern int HInit; /* Set to 1 when the volid hash table
				   is initialized */
extern const char *VSalvageMessage; /* Common message used when the volume goes
				       off line */
extern int VolDebugLevel; /* Controls level of debugging information */
extern int AllowResolution; /* global flag to turn on dir. resolution */
void VInitVolumePackage(int nLargeVnodes, int nSmallVnodes,
                        int DoSalvage) EXCLUDES_TRANSACTION;
int VInitVolUtil(ProgramType pt);
void VInitServerList(const char *host);
int VConnectFS();
void VDisconnectFS();
void VUCloneVolume(Error *, Volume *, Volume *) EXCLUDES_TRANSACTION;
void VListVolumes(char **buf, unsigned int *buflen) EXCLUDES_TRANSACTION;
void VGetVolumeInfo(Error *ec, char *key, VolumeInfo *info);
const char *VGetVolumeLocation(VolumeId vid);
Volume *VGetVolume(Error *ec, VolumeId volumeId);
void VPutVolume(Volume *vp);
Volume *VAttachVolume(Error *ec, VolumeId volumeId,
                      int mode) REQUIRES_TRANSACTION;
void VDetachVolume(Error *ec, Volume *vp) REQUIRES_TRANSACTION;
void VUpdateVolume(Error *ec, Volume *vp) REQUIRES_TRANSACTION;
int VAllocBitmapEntry(Error *ec, Volume *vp, struct vnodeIndex *index,
                      int stride, int ix, int count);
int VAllocBitmapEntry(Error *ec, Volume *vp, struct vnodeIndex *index,
                      VnodeId vnode);
void VFreeBitMapEntry(Error *ec, struct vnodeIndex *index, int bitNumber);
int VolumeNumber(char *name);
char *VolumeExternalName(VolumeId volumeId);
Volume *VAttachVolumeById(Error *ec, char *partition, VolumeId volid,
                          int mode) REQUIRES_TRANSACTION;
void VOffline(Volume *vp, const char *message) REQUIRES_TRANSACTION;
void VForceOffline(Volume *vp) REQUIRES_TRANSACTION;
void VPurgeVolume(Volume *vp);
void VShutdown() EXCLUDES_TRANSACTION;
void VSetDiskUsage() EXCLUDES_TRANSACTION;
void SetVolDebugLevel(int);
void FreeVolume(Volume *vp);
void DeleteVolumeFromHashTable(Volume *vp);
void PrintVolumesInHashTable();
void InitLRU(int howmany);

/* 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)

/* Modes of attachment, for VAttachVolume[ByName] to convey to the
   file server */
/* Absolutely no updates will be done to the volume */
#define V_READONLY 1

/* 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_CLONE 2

/* General update or volume purge is possible. Volume must go offline */
#define V_UPDATE 3

/* A dump of the volume is requested; the volume can be served read-only during
 * this time */
#define V_DUMP 4

/* 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 */
#define V_SECRETLY 5

/* partition disk usage related routines */

/* exported routines */
Error VAdjustDiskUsage(Volume *vp, int blocks);
Error VCheckDiskUsage(Volume *vp, int blocks);
void PutVolObj(Volume **volptr, int LockLevel, int Dequeue);
int GetVolObj(VolumeId Vid, Volume **volptr, int LockLevel, int Enque,
              unsigned LockerAddress) EXCLUDES_TRANSACTION;

#endif /* VOLUME_INCLUDED */
