/* volume.h: AFS volume management
 *
 * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
 * Written by David Howells (dhowells@redhat.com)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version
 * 2 of the License, or (at your option) any later version.
 */

#ifndef _LINUX_AFS_VOLUME_H
#define _LINUX_AFS_VOLUME_H

#include "types.h"
#include "fsclient.h"
#include "kafstimod.h"
#include "kafsasyncd.h"
#include "cache.h"

typedef enum {
	AFS_VLUPD_SLEEP,		/* sleeping waiting for update timer to fire */
	AFS_VLUPD_PENDING,		/* on pending queue */
	AFS_VLUPD_INPROGRESS,		/* op in progress */
	AFS_VLUPD_BUSYSLEEP,		/* sleeping because server returned EBUSY */
	
} __attribute__((packed)) afs_vlocation_upd_t;

/*****************************************************************************/
/*
 * entry in the cached volume location catalogue
 */
struct afs_cache_vlocation
{
	uint8_t			name[64];	/* volume name (lowercase, padded with NULs) */
	uint8_t			nservers;	/* number of entries used in servers[] */
	uint8_t			vidmask;	/* voltype mask for vid[] */
	uint8_t			srvtmask[8];	/* voltype masks for servers[] */
#define AFS_VOL_VTM_RW	0x01 /* R/W version of the volume is available (on this server) */
#define AFS_VOL_VTM_RO	0x02 /* R/O version of the volume is available (on this server) */
#define AFS_VOL_VTM_BAK	0x04 /* backup version of the volume is available (on this server) */

	afs_volid_t		vid[3];		/* volume IDs for R/W, R/O and Bak volumes */
	struct in_addr		servers[8];	/* fileserver addresses */
	time_t			rtime;		/* last retrieval time */
};

#ifdef AFS_CACHING_SUPPORT
extern struct cachefs_index_def afs_vlocation_cache_index_def;
#endif

/*****************************************************************************/
/*
 * volume -> vnode hash table entry
 */
struct afs_cache_vhash
{
	afs_voltype_t		vtype;		/* which volume variation */
	uint8_t			hash_bucket;	/* which hash bucket this represents */
} __attribute__((packed));

#ifdef AFS_CACHING_SUPPORT
extern struct cachefs_index_def afs_volume_cache_index_def;
#endif

/*****************************************************************************/
/*
 * AFS volume location record
 */
struct afs_vlocation
{
	atomic_t		usage;
	struct list_head	link;		/* link in cell volume location list */
	struct afs_timer	timeout;	/* decaching timer */
	struct afs_cell		*cell;		/* cell to which volume belongs */
#ifdef AFS_CACHING_SUPPORT
	struct cachefs_cookie	*cache;		/* caching cookie */
#endif
	struct afs_cache_vlocation vldb;	/* volume information DB record */
	struct afs_volume	*vols[3];	/* volume access record pointer (index by type) */
	rwlock_t		lock;		/* access lock */
	unsigned long		read_jif;	/* time at which last read from vlserver */
	struct afs_timer	upd_timer;	/* update timer */
	struct afs_async_op	upd_op;		/* update operation */
	afs_vlocation_upd_t	upd_state;	/* update state */
	unsigned short		upd_first_svix;	/* first server index during update */
	unsigned short		upd_curr_svix;	/* current server index during update */
	unsigned short		upd_rej_cnt;	/* ENOMEDIUM count during update */
	unsigned short		upd_busy_cnt;	/* EBUSY count during update */
	unsigned short		valid;		/* T if valid */
};

extern int afs_vlocation_lookup(struct afs_cell *cell,
				const char *name,
				unsigned namesz,
				struct afs_vlocation **_vlocation);

#define afs_get_vlocation(V) do { atomic_inc(&(V)->usage); } while(0)

extern void afs_put_vlocation(struct afs_vlocation *vlocation);
extern void afs_vlocation_do_timeout(struct afs_vlocation *vlocation);

/*****************************************************************************/
/*
 * AFS volume access record
 */
struct afs_volume
{
	atomic_t		usage;
	struct afs_cell		*cell;		/* cell to which belongs (unrefd ptr) */
	struct afs_vlocation	*vlocation;	/* volume location */
#ifdef AFS_CACHING_SUPPORT
	struct cachefs_cookie	*cache;		/* caching cookie */
#endif
	afs_volid_t		vid;		/* volume ID */
	afs_voltype_t		type;		/* type of volume */
	char			type_force;	/* force volume type (suppress R/O -> R/W) */
	unsigned short		nservers;	/* number of server slots filled */
	unsigned short		rjservers;	/* number of servers discarded due to -ENOMEDIUM */
	struct afs_server	*servers[8];	/* servers on which volume resides (ordered) */
	struct rw_semaphore	server_sem;	/* lock for accessing current server */
};

extern int afs_volume_lookup(const char *name,
			     struct afs_cell *cell,
			     int rwpath,
			     struct afs_volume **_volume);

#define afs_get_volume(V) do { atomic_inc(&(V)->usage); } while(0)

extern void afs_put_volume(struct afs_volume *volume);

extern int afs_volume_pick_fileserver(struct afs_volume *volume,
				      struct afs_server **_server);

extern int afs_volume_release_fileserver(struct afs_volume *volume,
					 struct afs_server *server,
					 int result);

#endif /* _LINUX_AFS_VOLUME_H */