[BACK]Return to xfs_grio.c CVS log [TXT][DIR] Up to [Development] / xfs-linux

File: [Development] / xfs-linux / Attic / xfs_grio.c (download)

Revision 1.32, Thu Sep 15 21:55:27 1994 UTC (23 years, 1 month ago) by ajs
Branch: MAIN
Changes since 1.31: +11 -3 lines

Fix inode list walking for new inode list scheme.

#ident "$Header: /oss/CVS/cvs/xfs-linux/Attic/xfs_grio.c,v 1.32 1994/09/15 21:55:27 ajs Exp $"

#include <sys/types.h>
#include <sys/param.h>
#include <sys/errno.h>
#ifndef SIM
#include <sys/systm.h>
#endif
#include <sys/debug.h>
#include <sys/buf.h>
#include <sys/sema.h>
#include <sys/lock.h>
#ifdef SIM
#define _KERNEL
#endif
#include <sys/vnode.h>
#include <sys/grio.h>
#ifdef SIM
#undef _KERNEL
#endif
#include <sys/vfs.h>
#include <sys/kmem.h>
#include <sys/cred.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/ktime.h>
#include <sys/fs/xfs_types.h>
#include <sys/fs/xfs_log.h>
#include <sys/fs/xfs_inum.h>
#include <sys/fs/xfs_trans.h>
#include <sys/fs/xfs_sb.h>
#include <sys/fs/xfs_mount.h>
#include <sys/fs/xfs_alloc_btree.h>
#include <sys/fs/xfs_bmap_btree.h>
#include <sys/fs/xfs_ialloc_btree.h>
#include <sys/fs/xfs_btree.h>
#include <sys/fs/xfs_dinode.h>
#include <sys/fs/xfs_inode_item.h>
#include <sys/fs/xfs_inode.h>

#ifdef SIM
#include "sim.h"
#include "stdio.h"
#endif

/*
 * These routines determine if a griven file read or write request 
 * has been guaranteed rate I/O and marks the buffer accordingly.
 *
 *
 *
 */

#define LESS_THAN_ONE_SECOND(tv, nexttv)	\
      	(( tv.tv_sec < nexttv.tv_sec) ||	\
	       ((tv.tv_sec == nexttv.tv_sec) && (tv.tv_nsec < nexttv.tv_nsec)))

#if defined(DEBUG) && !defined(SIM)
extern int	grio_debug;
#define GRIO_DBPRNT( level, str)        \
        if (grio_debug > level) {       \
                printf(str);            \
        }
#else
#define GRIO_DBPRNT(s1, s2 )
#endif

#define IRELE(ip)	VN_RELE(XFS_ITOV(ip))

int xfs_grio_add_ticket( file_id_t *, int, char *);
int xfs_grio_remove_ticket( file_id_t *, char *);
int xfs_add_ticket_to_inode( xfs_inode_t *, int, struct reservation_id *);
void xfs_remove_ticket_from_inode( xfs_inode_t *, struct reservation_id *);
int ticket_lock( xfs_inode_t *);
void ticket_unlock( xfs_inode_t *, int);
extern int xfs_read_file(vnode_t *, uio_t *, int, cred_t *);
extern int xfs_write_file(vnode_t *, uio_t *, int, cred_t *);
extern int xfs_diordwr(vnode_t *,uio_t *, int, cred_t *,int);
extern int strncmp(char *, char *, int);
extern struct vfs *vfs_devsearch( dev_t );
STATIC int xfs_grio_issue_io( vnode_t *, uio_t *,int, cred_t *,int);
STATIC int xfs_crack_file_id(file_id_t *, dev_t *, xfs_ino_t *);
xfs_inode_t *xfs_get_inode ( dev_t, int);
grio_ticket_t *xfs_io_is_guaranteed( xfs_inode_t *, struct reservation_id *, int *);

#ifndef SIM
extern void fasthz_delay( struct timeval *);
extern void timestruc_sub( timestruc_t *, timestruc_t *);
extern void timestruc_fix( timestruc_t *);
#endif


/*
 * xfs_get_inode_from_inum()
 *
 *	This routine takes the dev_t of a file system and an
 *	inode number on that file system, and returns a pointer
 *	to the corresponding incore xfs inode structure.
 *
 * RETURNS:
 *	xfs_inode_t pointer on success
 *	NULL on failure
 *
 */
xfs_inode_t *
xfs_get_inode(  dev_t fs_dev, int ino)
{
        struct vfs		*vfsp;
        xfs_inode_t		*ip = NULL ;
	extern struct vfs	*vfs_devsearch( dev_t );

        vfsp = vfs_devsearch( fs_dev );
        if (vfsp) {
		/*
		 * Verify that this is an xfs file system.
		 */
#ifndef SIM
		if (strncmp(vfssw[vfsp->vfs_fstype].vsw_name, "xfs", 3) == 0) 
#endif
		{
                	ip = xfs_iget( XFS_VFSTOM( vfsp ), 
					NULL, ino, XFS_ILOCK_EXCL);

#ifdef DEBUG
			if (!ip) 
				printf("xfs_get failed on %d \n",ino);
#endif

		}
        } 
#ifdef DEBUG
	else {
		printf("vfs_devsearch failed \n");
	}
#endif
        return( ip );
}


/*
 * xfs_add_ticket_to_inode()
 *
 *	Add another ticket to the inode ticket list. The inode must
 *	be locked to perform this.
 *
 */
int
xfs_add_ticket_to_inode( xfs_inode_t *ip, int sz, struct reservation_id *id )
{
	int		ret = 0, s;
	grio_ticket_t	*ticket;

	/*
 	 * Check if ticket with this id is already on the list.
 	 */
	if (xfs_io_is_guaranteed( ip, id, &s ) ) {
		ret = -1;
	} else {
		if (ticket = kmem_zalloc( sizeof( grio_ticket_t), KM_SLEEP)) {
			ticket->sz     = sz;
			ticket->type   = NON_ROTATE_TYPE;
			ticket->id.ino = id->ino;
			ticket->id.pid = id->pid;
			if (id->vod_rotate_slot != NULL_VOD_SLOT) {
				ticket->rotator_slot = id->vod_rotate_slot;
				ticket->rotator_group_size = id->vod_group_size;
				ticket->type = ROTATE_TYPE;
			}

			if (ip->i_ticket) 
				ticket->nextticket = ip->i_ticket;
			/*
			 * This write must be atomic, otherwise
			 * the exclusive ticket lock must be held.
			 */
			ip->i_ticket = ticket;
		}
	}
	ticket_unlock(ip, s);
	return(ret);
}

/*
 * xfs_grio_add_ticket()
 *
 *	Add the rate guarantee reservation of numios I/Os per
 *	second to the given xfs inode.
 *
 *  RETURNS:
 *	0 on success
 *	-1 on failure
 */
int
xfs_grio_add_ticket( file_id_t *fileidp, int sz, char *idptr)
{
	int			ret = -1;
	dev_t			fs_dev;
	xfs_ino_t		ino;
	xfs_inode_t		*ip;
	struct reservation_id	id;


	xfs_crack_file_id( fileidp, &fs_dev, &ino);

#if defined(DEBUG) && !defined(SIM)
	if (grio_debug)
		printf("add ticket: ino = %llx, dev = %x \n",
					(__int64_t)ino, fs_dev);
#endif

	if (copyin(idptr, (caddr_t)&id, sizeof(id))) {
#ifdef DEBUG
		printf("COULD NOT GET ID \n");
#endif
		ret = EFAULT;
		return( ret );
	}

        /*
         * Lock the inode IOLOCK_EXCL so that the i_ticket
         * list in the inode can be safely updated.
         */
        if (ip = xfs_get_inode( fs_dev, ino )) {
		ret = xfs_add_ticket_to_inode( ip, sz, &id );
		xfs_iunlock( ip, XFS_ILOCK_EXCL );
		IRELE( ip );
        }
#ifdef DEBUG
        else {
                printf("could not get ip to add ticket to !\n");
        }
#endif


	return(ret);
}

/*
 * xfs_remove_ticket_from_inode()
 *
 *	This routine removes the ticket with the matching id from the
 *      inode ticket list. The inode ticket list is protected by per
 *      inode ticket list lock. This lock is held shared when processes
 *      are scanning the ticket list and updating tickets. It is held
 *      exclusive when a ticket is being removed from the list.
 *
 * RETURNS:
 *      none
 */
void
xfs_remove_ticket_from_inode( xfs_inode_t *ip, struct reservation_id *id)
{
	grio_ticket_t *ticket, *previousticket;
	int s;

	s = ticket_lock( ip );
	if (ticket = ip->i_ticket) {
		if (MATCH_ID((&(ticket->id)), id)) {
			ip->i_ticket = ticket->nextticket;
		} else {
			while (ticket && (!(MATCH_ID((&(ticket->id)), id)))) {
				previousticket = ticket;
				ticket = ticket->nextticket;
			}
			if (ticket) 
				previousticket->nextticket = ticket->nextticket;
		}
		if (ticket) {
			kmem_free( ticket, sizeof( grio_ticket_t ) );
		}
	}
	ticket_unlock( ip, s );
}

/*
 * xfs_grio_remove_ticket()
 *
 *	Remove the rate guarantee reservation with the given id
 *	from the given xfs inode.
 *
 *  RETURNS:
 *	0 on success
 *	-1 on failure
 */
int
xfs_grio_remove_ticket( file_id_t *fileidp, char *idptr)
{
	dev_t			fs_dev;
	xfs_ino_t		ino;
	xfs_inode_t 		*ip;
	struct reservation_id	id;

	xfs_crack_file_id( fileidp, &fs_dev, &ino);

#if defined(DEBUG) && !defined(SIM)
	if (grio_debug) {
		printf("remove ticket: ino = %llx, dev = %x \n",
				(__int64_t)ino, fs_dev);
	}
#endif

	if (copyin(idptr, (caddr_t)&id, sizeof(id))) {
#ifdef DEBUG
		printf("COULD NOT GET ID \n");
#endif
		return( EFAULT );
	}

	if (ip = xfs_get_inode( fs_dev, ino)) {
		xfs_remove_ticket_from_inode (ip, &id);
		xfs_iunlock( ip, XFS_ILOCK_EXCL );
		IRELE( ip );
	}
	return(0);
}

/*
 * xfs_io_is_guaranteed()
 *
 *	Check if a process using the given pid and fd has
 *	a ticket for guaranteed rate I/O on the given xfs
 *	file. If it does, check if the I/O size requested is
 *	within the guaranteed amount.
 *
 *	If the requested I/O is larger than the guaranteed 
 *	I/O, issue part of the request and put the requestor to
 *	sleep.
 *
 * RETURNS:
 *	0 if there is no guarantee
 *	non-zero if there is a guarantee
 */
grio_ticket_t *
xfs_io_is_guaranteed( xfs_inode_t *ip, struct reservation_id *id, int *s)
{
	grio_ticket_t *ticket;

	*s = ticket_lock( ip );
	ticket = ip->i_ticket;

	while (ticket && (!MATCH_ID((&(ticket->id)), id))) {
		ticket = ticket->nextticket;
	} 
	return(ticket);
}


/*
 * xfs_grio_req()
 *
 *	This routine issues user guaranteed rate I/O requests. If the
 *	size of the request is larger than the amount guaranteed for the
 *	user, this routine breaks up the request into chucks of the size 
 *	of the guaranteed amount. It issues one of the guaranteed amount
 * 	size requests each second.
 *
 *
 * RETURNS:
 *	0 on success
 *	non-0 on failure.
 */
int
xfs_grio_req( xfs_inode_t *ip, 
	struct reservation_id *id, 
	uio_t *uiop, 
	int ioflag,
	cred_t *credp,
	off_t	offset,
	int rw)
{
	int 		sz, ret = 0, remainingio, thisioreq, set_size, s, eof = 0; 
	int		which_disk, current_disk, num_sec, sec, delay_ticks;
	time_t		snap_lbolt;
	vnode_t 	*vp;
	timestruc_t	tv, nexttv;
	grio_ticket_t 	*ticket;
	struct	timeval	tvl;

retry_request:

        /*
         * Determine if this request has a guaranteed rate of I/O.
         */
        if (ticket = xfs_io_is_guaranteed( ip, id, &s)) {
		/*
 		 * Mark this request as being rate guaranteed. 
		 */
		ioflag |= IO_GRIO;

		if ( ROTATE_TICKET(ticket) ) {
			ASSERT(uiop->uio_resid == ticket->sz);

			snap_lbolt 	= lbolt;
			set_size 	= ticket->rotator_group_size;
			sec 		= (snap_lbolt / HZ) % set_size;

			which_disk 	= (offset / ticket->sz) % set_size;
			current_disk 	= (sec + ticket->rotator_slot) % 
						set_size;

			if (which_disk == current_disk) {
				/*
				 * Fall thru and issue the request.
				 * This is the correct disk at this time
				 * for a request in this slot.
				 */
				;
			} else {

#ifdef CLOSER_TIMING
				if (current_disk > which_disk) {
					num_sec =  set_size - 1 - 
						current_disk + which_disk;
				} else {
					ASSERT( which_disk > current_disk );
					num_sec = which_disk - current_disk - 1;
				}

				delay_ticks = HZ - (snap_lbolt % HZ);
				delay_ticks += ( num_sec * HZ);

#else
				delay_ticks = 1;
#endif

                        	ticket_unlock(ip, s );
		                delay( delay_ticks );
				goto retry_request;
			}
        		ticket->lastreq.tv_sec  = 0;
        		ticket->lastreq.tv_nsec = 0;
		}

		/*
	 	 * 1) Determine the time of the last request.
	 	 *    *) if it has been more than 1 second, zero out
	 	 *	the iothissecond field and set the new time
		 *    *) if if has been less than 1 second since last req
		 *	continue.
	 	 * 2) Check the size of the request,
		 *	*) if sz >= (reqsize + iothissecond)
		 *		issue the whole request and update iothissecond.
 		 *	*) if sz < (reqsize + iothissecond)
	 	 *		issue a request of the size 
		 *			reqsize1 = sz - iothissecond.
		 *		and update iothissecond
		 */

		ret = 0;
		remainingio = uiop->uio_resid;
		uiop->uio_resid = 0;
		while ((remainingio) && (!ret) && (!eof)) {

	       		/*
         		 * Check if the request is within the time limits
         		 * of the rate guarantee.
         		 */
        		nanotime(&tv);

        		/*
         	 	 * Determine the time that the next 
			 * request can be issued.
         	 	 */
        		nexttv.tv_sec  = ticket->lastreq.tv_sec + 1;
        		nexttv.tv_nsec = ticket->lastreq.tv_nsec;
			
			if (LESS_THAN_ONE_SECOND( tv, nexttv ) ) {
		 		/*
			 	 * It has been less than 1 second 
			 	 * since the last request.
			 	 */
				;
			} else {
				/*
			 	 * If has been more than 1 second	
			 	 * since the last request.	
			 	 */
				ticket->iothissecond    = 0;
				ticket->lastreq.tv_sec  = tv.tv_sec;
				ticket->lastreq.tv_nsec = tv.tv_nsec;
			}

			/*
			 * Only allow a single request per process each second.
			 */
                	if (ticket->iothissecond ==  0) {

                        	/*
                         	 * Issue the largest I/O possible. 
                         	 */
				thisioreq = ticket->sz - ticket->iothissecond;
				if (thisioreq > remainingio)
					thisioreq = remainingio;

				uiop->uio_resid 	 = thisioreq;
				uiop->uio_iov[0].iov_len = thisioreq; 
				remainingio		-= thisioreq;

				ticket->iothissecond    += thisioreq; 

                        	ticket_unlock(ip, s);
				vp = XFS_ITOV(ip);

				/*
				 * Issue the request.
				 */
				ret = xfs_grio_issue_io( vp, 
					uiop, ioflag, credp, rw);

				/*
			 	 * Check for end of file.
			 	 */
				if ((uiop->uio_resid != 0)) {
					eof = 1;
				}
			} else {
                		/*
                 		 * The user issued the next request too soon, 
				 * or the I/O request was too large. The
                 		 * process will be put to sleep until the next 
				 * time slice.
                 		 * The granularity of this delay is 1/fasthz 
				 * (1 millisecond).
                 		 */
                        	ticket_unlock(ip, s );
                		GRIO_DBPRNT(2,"request issued too soon \n");

#ifdef SIM
				delay(1);
#else
		                timestruc_sub( &nexttv, &tv );
               			timestruc_fix( &nexttv );

                		TIMESTRUC_TO_TIMEVAL(&nexttv, &tvl);

		                fasthz_delay( &tvl );
#endif
			}
			/*
		 	 * Check if rate guarantee was removed while
		 	 * I/O was taking place.
		 	 */
			if (( ticket = xfs_io_is_guaranteed(ip,id,&s)) == NULL){
       				ticket_unlock(ip, s);
		        	uiop->uio_resid += remainingio;
				uiop->uio_iov[0].iov_len = uiop->uio_resid;
				if (uiop->uio_resid) {
					vp = XFS_ITOV(ip);
					ret = xfs_grio_issue_io(vp, uiop, 
						ioflag, credp, rw);
				}
				return(ret);
			}
                }

		/*
		 * Add unperformed I/O back into resid.
		 */
		uiop->uio_resid += remainingio;
		uiop->uio_iov[0].iov_len = uiop->uio_resid;

       		ticket_unlock(ip, s);
	} else {
       		ticket_unlock(ip, s);
		vp = XFS_ITOV(ip);

#ifndef SIM
     		ASSERT(ismrlocked(&ip->i_iolock, MR_ACCESS | MR_UPDATE) != 0);
#endif
		ret = xfs_grio_issue_io(vp, uiop, ioflag, credp, rw);
#ifndef SIM
     		ASSERT(ismrlocked(&ip->i_iolock, MR_ACCESS | MR_UPDATE) != 0);
#endif


	}
        return (ret) ;
}




/*
 * xfs_grio_issue_io()
 *	This routine issues the actual I/O request using the file 
 *	type and I/O operation.
 *
 * RETURNS:
 *	0 on success
 *	-1 on failure
 */
STATIC int
xfs_grio_issue_io( vnode_t *vp, 
	uio_t   *uiop, 
	int     ioflag,
	cred_t  *credp,
	int     rw)
{
	int ret;

	/*
  	 * Currently rate guaranteed I/O can only be issued IO_DIRECT.
	 */
	if ((ioflag & IO_GRIO) && (!(ioflag & IO_DIRECT))) {
		ret = -1;
#ifdef DEBUG
		printf("File is rate guaranteed - cannot user buffer cache.\n");
#endif
		return( ret );
	}

	if (rw == UIO_READ) {
		if (ioflag & IO_DIRECT)
			ret = xfs_diordwr( vp, uiop, ioflag, credp, B_READ);
		else 
			ret = xfs_read_file(vp, uiop, ioflag, credp);
	} else {
		if (ioflag & IO_DIRECT)
			ret = xfs_diordwr( vp, uiop, ioflag, credp, B_WRITE);
		else
			ret = xfs_write_file(vp, uiop, ioflag, credp);
	}
	return( ret );
}


/*
 * ticket_lock()
 *      Locks the per inode ticket lock in exclusive mode.
 *
 * RETURNS:
 *	The current spl level.
 */
int
ticket_lock(xfs_inode_t *ip)
{
	int s;

#ifndef SIM
	s = splockspl(ip->i_ticketlock, splhi);
#endif
	return( s );
}

/*
 * ticket_unlock()
 *      Unlocks the per inode ticket lock.
 *
 * RETURNS:
 *	none
 */
void
ticket_unlock(xfs_inode_t *ip, int s)
{
#ifndef SIM
	spunlockspl(ip->i_ticketlock, s);
#endif
}


/*
 * xfs_get_file_extents()
 *	This routine creates the cononical forms of all the extents
 *	for the given file and returns them to the user.
 *
 *
 *
 *  RETURNS:
 *	0 on success
 *	~0 on failure
 */
int
xfs_get_file_extents(file_id_t *fileidp, xfs_bmbt_irec_t extents[], int *count)
{
	int			i, recsize, num_extents = 0, ret = 0;
	dev_t			fs_dev;
	xfs_ino_t		ino;
	xfs_inode_t 		*ip;
	xfs_bmbt_rec_t 		*ep;
	xfs_bmbt_irec_t 	thisrec;
	grio_bmbt_irec_t	*grec;

	xfs_crack_file_id( fileidp, &fs_dev, &ino);

#if defined(DEBUG) && !defined(SIM)
	if (grio_debug) {
		printf("get file extents: ino = %llx, dev = %x \n",
				(__int64_t)ino, fs_dev);
	}
#endif
	/*
 	 * Get the inode.
	 */
	if (!(ip = xfs_get_inode( fs_dev, ino ))) {
		ret = ENOENT;
		if (copyout( &num_extents, count, sizeof( num_extents))) {
			ret = EFAULT;
		}
		return( ret );
	}

	/*
	 * Get the number of extents in the file.
	 */
	num_extents = ip->i_bytes / sizeof(*ep);
	if (num_extents) {

		/*
		 * Copy the extents if they exist.
		 */
		ASSERT(num_extents <  XFS_MAX_INCORE_EXTENTS);

		recsize = sizeof(grio_bmbt_irec_t) * num_extents;
		grec = kmem_alloc(recsize, KM_SLEEP );
		ASSERT(grec);

		ep = ip->i_u1.iu_extents;

		for (i = 0; i < num_extents; i++, ep++) {
			/*
 			 * copy extent numbers;
 			 */
			xfs_bmbt_get_all(ep, &thisrec);
			grec[i].br_startoff 	= thisrec.br_startoff;
			grec[i].br_startblock 	= thisrec.br_startblock;
			grec[i].br_blockcount 	= thisrec.br_blockcount;
		}

		if (copyout(grec, extents, recsize )) {
			ret = EFAULT;
		}
		kmem_free(grec, 0 );
	}

	/* 
	 * copyout to user space along with count.
 	 */
	if (copyout( &num_extents, count, sizeof( num_extents))) {
		ret = EFAULT;
	}

	xfs_iunlock( ip, XFS_ILOCK_EXCL );
	IRELE( ip );
	return( ret );
}

/*
 * xfs_get_file_rt()
 *	This routine determines if the given file has real time
 *	extents. If so a 1 is written to the user memory pointed at
 *	by rt, if not a 0 is written.
 *
 *
 * 
 */
xfs_get_file_rt( file_id_t *fileidp, int *rt)
{
	int 		inodert = 0, ret = 0;
	dev_t		fs_dev;
	xfs_ino_t	ino;
	xfs_inode_t 	*ip;

	xfs_crack_file_id( fileidp, &fs_dev, &ino);

#if defined(DEBUG) && !defined(SIM)
	if (grio_debug) {
		printf("get file rt: ino = %llx, dev = %x \n",
				(__int64_t)ino, fs_dev);
	}
#endif

	/*
 	 * Get the inode.
	 */
	if (!(ip = xfs_get_inode( fs_dev, ino ))) {
		return( ENOENT );
	}

	/*
	 * Check if the inode is marked as real time.
	 */
	if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) {
		inodert = 1;
	}

	/*
 	 * Copy the results to user space.
 	 */
	if (copyout( &inodert, rt, sizeof( rt))) {
		ret = EFAULT;
	}

	xfs_iunlock( ip, XFS_ILOCK_EXCL );
	IRELE( ip );
	return( ret );

}


/*
 * xfs_get_block_size()
 *	This routine determines the block size of the given
 *	file system copies it to the user memory pointed at by fs_size.
 *
 * RETURNS:
 *	0 on success
 *	-1 on failure
 */
xfs_get_block_size(dev_t fsdev, int *fs_size)
{
	int 		ret = 0;
	struct vfs	*vfsp;

	if (vfsp = vfs_devsearch( fsdev )) {
		if (copyout(&(vfsp->vfs_bsize), fs_size, sizeof(*fs_size))) {
			ret = EFAULT;
		}
	} else {
		ret = -1;
	}
	return( ret );
}


/*
 * xfs_remove_all_tickets()
 *	This routine is called by the xfs_remove_all_tickets() routine
 *	to remove the rate guarantee tickets from the inodes on a 
 *	specific file system. This routine removes the guarantee tickets
 *	and frees the memory space.
 *
 * RETURNS:
 *	none
 */
STATIC void
xfs_remove_tickets_from_fs(vfs_t *vfsp)
{
	xfs_mount_t 	*mp;
	xfs_inode_t 	*ip;
	grio_ticket_t	*ticket, *nextticket;


	mp = XFS_VFSTOM(vfsp);
	XFS_MOUNT_ILOCK(mp);
	if (mp->m_inodes == NULL) {
		XFS_MOUNT_IUNLOCK(mp);
		return;
	}

	ip = mp->m_inodes;
	do {
		for (ticket = ip->i_ticket; ticket; ticket = nextticket) {
			nextticket = ticket->nextticket;
			kmem_free( ticket, sizeof(grio_ticket_t));
		}
		ip->i_ticket = NULL;
		ip = ip->i_mnext;
	} while (ip != mp->m_inodes);
	XFS_MOUNT_IUNLOCK(mp);
}
	

/*
 * xfs_remove_all_tickets()
 *	This routine is called when the guarantee granting daemon
 *	is started to remove and previous guarantees that it does
 *	not know about. This only has meaning when the daemon crashes
 *	and needs to be restarted.
 *
 * RETURNS:
 * 	always returns 0
 */
int
xfs_remove_all_tickets()
{
	int 		s;
	vfs_t		*vfsp;
	extern int	xfs_type;
	extern vfs_t	*rootvfs;
	extern lock_t	vfslock;
	extern int	xfs_fstype;

	/*
 	 * For each file system on the machine.
	 */
#ifndef SIM
	s = splock(vfslock);
#endif
	for (vfsp = rootvfs; vfsp != NULL; vfsp = vfsp->vfs_next) {
		/*
 		 * If this is an xfs file system ...
		 */
		if (vfsp->vfs_fstype == xfs_fstype) {
			/*
 	 		 * Remove the tickets from the inodes.
 	 		 */
			xfs_remove_tickets_from_fs(vfsp);
		}
	}
#ifndef SIM
	spunlock(vfslock, s);
#endif
	return(0);
}

/*
 * xfs_remove_grio_guarantee()
 *	This routine constructs a grio msg structure to send to 
 *	the guarantee granting daemon which instructs it to remove 
 *	the rate guarantee for the given pid and inode. The message is
 * 	sent asynchronously.
 *
 * RETURNS:
 *	0 on success
 *	non zero on failure
 */
int
xfs_remove_grio_guarantee(xfs_inode_t *ip, pid_t pid)
{
	int		ret;
	grio_blk_t 	grioblk;
	extern int	grio_issue_async_grio_req(grio_blk_t *);
	extern void	bzero( void *, int);

	bzero(&grioblk, sizeof(grio_blk_t));

	grioblk.resv_type 	= GRIO_UNRESV_FILE_ASYNC;
	grioblk.procid 		= pid;
	grioblk.ino		= ip->i_ino;
	grioblk.fs_dev		= ip->i_dev;

	/*
 	 * Issue the message, do not wait for completion.
 	 */
	ret = grio_issue_async_grio_req(&grioblk);
	return( ret );
}

/*
 * xfs_mark_inode_grio()
 *	This routine sets the XFS_IGRIO flag from the incore
 *	inode structure of the file described by fileidp.
 *
 * RETURNS:
 *	0 on success
 *	1 on failure
 */
xfs_mark_inode_grio( file_id_t *fileidp)
{
	dev_t		fs_dev;
	xfs_ino_t	ino;
	xfs_inode_t	*ip;

	xfs_crack_file_id(fileidp, &fs_dev, &ino);

#if defined(DEBUG) && !defined(SIM)
	if (grio_debug) {
		printf("mark inode: ino = %llx, dev = %x \n",
			(__int64_t)ino, fs_dev);
	}
#endif
	/*
 	 * get inode
	 */
	if (!(ip = xfs_get_inode( fs_dev, ino ))) {
		return( 1 );
	}

	ip->i_flags |= XFS_IGRIO;

	xfs_iunlock( ip, XFS_ILOCK_EXCL );
	IRELE( ip );
	return( 0 );

}

/*
 * xfs_clear_inode_grio()
 *	This routine clears the XFS_IGRIO flag from the incore
 *	inode structure of the file described by fileidp.
 *
 * RETURNS:
 *	0 on success
 *	1 on failure
 */
int
xfs_clear_inode_grio( file_id_t *fileidp)
{
	dev_t		fs_dev;
	xfs_ino_t	ino;
	xfs_inode_t	*ip;

	xfs_crack_file_id(fileidp, &fs_dev, &ino);

#if defined(DEBUG) && !defined(SIM)
	if (grio_debug) {
		printf("clear inode: ino = %llx, dev = %x \n",
			(__int64_t)ino, fs_dev);
	}
#endif

	/*
 	 * Get the inode.
	 */
	if (!(ip = xfs_get_inode( fs_dev, ino ))) {
		return( 1 );
	}

	ip->i_flags &= ~XFS_IGRIO;

	xfs_iunlock( ip, XFS_ILOCK_EXCL );
	IRELE( ip );
	return( 0 );
}

/*
 * xfs_crack_file_id()
 *	This routine takes the guarantee granting daemon's version of
 *	the file inode number and the file system dev_t, and coverts
 *	them to the kernel's version. The ggd handles all inode numbers
 *	as 64 bit quantities, the kernel may use 32 or 64 bits to define
 *	inode numbers.
 *	The 
 *
 * RETURNS:
 *	0 on success
 *	non 0 no failure
 */
STATIC int
xfs_crack_file_id(file_id_t *ufile_idp, dev_t *fs_devp, xfs_ino_t *inop)
{
	file_id_t	file_id;
	
	if (copyin((char *)ufile_idp, (caddr_t)&file_id, sizeof(file_id))) {
#ifdef DEBUG
		printf("Could not access user memory.\n");
		ASSERT(0);
#endif
		return( EFAULT );
	}

	*fs_devp = file_id.fs_dev;
	*inop    = file_id.ino;
	return(0);
}