/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1988
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/* $Header:afs_vfsops.c 12.6$ */
/* $ACIS:afs_vfsops.c 12.6$ */
/* $Source: /ibm/acis/usr/sys/afs/RCS/afs_vfsops.c,v $ */

#ifndef lint
static char *rcsid = "$Header:afs_vfsops.c 12.6$";
#endif

#include "../h/types.h"
#include "../h/param.h"
#include "../h/time.h"
#include "../h/kernel.h"
#include "../h/socket.h"
#include "../h/socketvar.h"
#include "../h/protosw.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/file.h"
#include "../h/uio.h"
#include "../h/vfs.h"
#include "../h/vnode.h"
#include "../ufs/inode.h"
#include "../netinet/in.h"
#include "../h/mbuf.h"
#include "../rpc/types.h"
#include "../rpc/xdr.h"

#include "../afs/osi.h"
#define RFTP_INTERNALS 1
#include "../afs/r.h"
#include "../afs/rftp.h"

#include "../afs/lock.h"
#include "../afs/volerrors.h"
#include "../afsint/rvice.h"
#include "../afsint/rvaux.h"
#include "../afs/afs.h"

int afs_mount();
int afs_unmount();
int afs_root();
int afs_statfs();
int afs_sync();
int afs_vget();

struct vfs *afs_globalVFS = 0;
extern int afs_running;
extern int afs_daemons_running;
extern short afs_brsDaemons;
extern char *r_GetRequest_sleep_addr;
extern struct r_server *afs_server;
extern int selwait;
extern int brsInit;
extern int initd;
extern int r_initialized;
extern int kmem_tally;
extern int kmem_alloc_tallies;
extern int kmem_free_tallies;

struct vfsops afs_vfsops = {
    afs_mount,
    afs_unmount,
    afs_root,
    afs_statfs,
    afs_sync,
#ifdef AFS_VFS34
    afs_vget,
#endif
};

afs_vfsops_cleanup() {
    afs_globalVFS = 0;
}

afs_mount(afsp, path, data)
    struct vfs *afsp;
    char *path;
    caddr_t data; {
    afs_globalVFS = afsp;
    afsp->vfs_bsize = 8192;
    return 0;
}

afs_unmount (afsp)
    struct vfs *afsp; {
	/*
	 * make sure we are mounted
	 */
	if (afsp != afs_globalVFS) {
		return EINVAL;
	}

	/*
	 * remove all the user connections
	 */
	afs_Clear_Users();


	/*
	 * turn of the kernel daemons
	 */
	afs_running = 0;
	osi_Wakeup(&afs_brsDaemons);   /* Wakeup afs_BackgroundDaemon */
	osi_Wakeup(r_GetRequest_sleep_addr); /* Wakeup r_GetRequest */  
	wakeup(&selwait);
	while (afs_daemons_running > 0) {
		sleep(&afs_daemons_running,PZERO-1);
	}

	/*
	 * invalidate the cache and free the memory
	 */
	afs_FreeCache();

	/*
	 * clear global data structures
	 */

	soclose(afs_server->socket);
	DCleanUp();

	afs_daemons_cleanup();
	afs_pioctl_cleanup();
	afs_vfsops_cleanup();
	afs_vnodeops_cleanup();
	afs_test_cleanup();
	buffer_cleanup();
	cache_cleanup();
	callback_cleanup();
	osi_cleanup();
	osi_file_cleanup();
	osinet_cleanup();
	physio_cleanup();
	r_cleanup();
	resource_cleanup();
	rftp_cleanup();

	return 0;
}

afs_root (afsp, avpp)
    struct vfs *afsp;
    struct vnode **avpp; {
    register long code;
    struct vrequest treq;
    register struct vcache *tvp;

    afs_InitReq(&treq, &osi_cred);
    if (code = afs_CheckInit()) return code;
    tvp = afs_GetVCache(&afs_rootFid, &treq);
    /* we really want this to stay around */
    if (!tvp) return ENOENT;
    if (tvp->vrefCount < 20000) tvp->vrefCount++;
    tvp->v.v_flag |= VROOT;	    /* No-op on Ultrix 2.2 */
    afs_globalVFS = afsp;
    *avpp = (struct vnode *) tvp;
    return 0;
}

afs_sync(afsp)
    struct vfs *afsp; {
    return 0;
}

afs_statfs(afsp, abp, avcp)
    register struct vfs *afsp;
    struct statfs *abp; 
    register struct vcache *avcp;{
    register struct conn *tc;
    struct vrequest treq;
    struct VolumeStatus volstat;
    struct BBS Name, OfflineMsg, MOTD;
    char name[32],offmsg[256],motd[256];
    int code;

    afs_InitReq(&treq, u.u_cred);
    Name.SeqBody = name;
    Name.MaxSeqLen = sizeof(name);
    Name.SeqLen = 0;
    OfflineMsg.SeqBody = offmsg;
    OfflineMsg.MaxSeqLen = sizeof(offmsg);
    OfflineMsg.SeqLen = 0;
    MOTD.SeqBody = motd;
    MOTD.MaxSeqLen = sizeof(motd);
    MOTD.SeqLen = 0;

    do {
	tc = afs_Conn(&avcp->fid, &treq);
	if (tc) {
#ifdef NINTERFACE
	      code = AFS_GetVolumeStatus(tc->id, avcp->fid.Fid.Volume, &volstat,
					      &Name, &OfflineMsg, &MOTD);
#else
	      code = RViceGetVolumeStatus(tc->id, avcp->fid.Fid.Volume,&volstat,
					      &Name, &OfflineMsg, &MOTD);
#endif
	} else {
	       code = -1;
	}
     } while (afs_Analyze(tc, code, &avcp->fid, &treq));
	
     if (code) return(afs_CheckCode(code,&treq));
     abp->f_bsize = 1024;
     abp->f_blocks = volstat.MaxQuota ? volstat.MaxQuota:volstat.PartMaxBlocks;
     if (abp->f_blocks < volstat.BlocksInUse) {
	abp->f_blocks = volstat.BlocksInUse;
     }
     abp->f_bfree = abp->f_blocks - volstat.BlocksInUse;
     abp->f_bavail = MIN(abp->f_bfree,volstat.PartBlocksAvail);
     abp->f_files = -1;
     abp->f_ffree = -1;
     bcopy((caddr_t)&afsp->vfs_fsid, (caddr_t)&abp->f_fsid, sizeof(fsid_t));
     return(0);
}

#ifdef AFS_VFS34
/* get a vnode by fid; not used by us */
afs_vget() {
    panic("afs vget");
}
#endif
