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

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

Revision 1.9, Wed Dec 15 01:53:02 1993 UTC (23 years, 10 months ago) by miken
Branch: MAIN
Changes since 1.8: +365 -366 lines

Just reformat to 8 space indents and remove or add comments.

/*
 * High level interface routines for log manager
 */

#include <sys/types.h>

#include <sys/param.h>
#ifdef SIM
#define _KERNEL
#endif
#include <sys/sysmacros.h>
#include <sys/buf.h>
#ifdef SIM
#undef _KERNEL
#include <bstring.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#else
#include <sys/kmem.h>
#endif
#include <sys/sema.h>
#include <sys/uuid.h>
#include <sys/vnode.h>

#include "xfs_inum.h"
#include "xfs_types.h"
#include "xfs_sb.h"		/* depends on xfs_types.h & xfs_inum.h */
#include "xfs_trans.h"
#include "xfs_mount.h"		/* depends on xfs_trans.h & xfs_sb.h */
#include "xfs_log.h"		/* depends on xfs_mount.h */

#ifndef LOG_DEBUG
int
xfs_log_reserve(struct xfs_mount *mp, int reserve, int flags)
{
        return (1);
}

#else


#include "xfs_log_priv.h"

/* Local function prototypes */
STATIC void log_alloc(xfs_mount_t *mp, dev_t log_dev);
STATIC void log_clean(log_t *log);
STATIC void log_commit_record(xfs_mount_t *mp, log_ticket_t *ticket);
STATIC void log_copy(in_core_log_t *, xfs_log_iovec_t region[], int i, int n,
		     int offset, xfs_lsn_t *lsn);
STATIC void log_sync(log_t *log, xfs_lsn_t *lsn, uint flags);
STATIC void log_unalloc(void);
STATIC int  log_write(xfs_mount_t *mp, xfs_log_iovec_t	region[], int nentries,
		      xfs_log_ticket_t	tic, int commit);


/*
 * NOTES:
 *
 *	1. currblock field gets updated at startup and after in-core logs
 *		are written out to the disk.
 *
 */

/*
 * purpose: This function will take a log sequence number and check to
 *	see if that lsn has been flushed to disk.  If it has, then the
 *	callback function is called with the callback argument.
 */
void
xfs_log_notify(xfs_mount_t *mp,		/* mount of partition */
	       xfs_lsn_t   lsn,		/* lsn looking for */
	       void	   callback_func(void *),
	       void	   *callback_arg)
{
	log_t *log = mp->m_log;
	
	if (log->l_iclog->ic_state == LOG_CURRENT ||
	    log->l_iclog->ic_state == LOG_SYNCING) {
		printf("help");
	}
}	/* xfs_log_notify */


/*
 *
 */
void
xfs_log_done(xfs_mount_t	*mp,
	     xfs_log_ticket_t	tic)
{
	log_t		*log    = mp->m_log;
	log_ticket_t	*ticket = (xfs_log_ticket_t) tic;
	
	log_commit_record(mp, ticket);
	log_putticket(log, ticket);
}	/* xfs_log_done */


/*
 * purpose: Force the in-core log to disk.  If flags == XFS_LOG_SYNC,
 *	the force is done synchronously.
 */
int
xfs_log_force(xfs_mount_t	*mp,
	      xfs_log_ticket_t	ticket,
	      uint		flags)
{
	xfs_lsn_t	lsn;
	log_t		*log = mp->m_log;
	
	ASSIGN_LSN(lsn, log->l_cycle, log->l_currblock);
	
	if (flags & XFS_LOG_FORCE)
		log_sync(log, &lsn, flags);
	else if (flags & XFS_LOG_URGE)
		return -1;	/* not implemented yet */
	else
		return -1;	/* XFS_LOG_FORCE | XFS_LOG_URGE must be set */
	
}	/* xfs_log_force */


/*
 * purpose: Given an old transaction id for a <mp, slot> pair, replace
 *	it with a new transaction id.  Do not change the reservation.
 */
int
xfs_log_new_transaction(xfs_mount_t	 *mp,	/* mount point */
			xfs_log_ticket_t tic,
			xfs_tid_t	 otid,	/* old tid */
			xfs_tid_t	 ntid)	/* new tid */
{
	log_ticket_t *ticket = (log_ticket_t *)tic;
	
	if (ticket->t_tid != otid)
		return (-1);
	ticket->t_tid = ntid;
}


/*
 * Initialize log manager data.
 */
int
	xfs_log_init()
{
}


/*
 *  1. Reserve an amount of on-disk log space and return a ticket corresponding
 *	to the reservation.
 *  2. Potentially, push buffers at tail of log to disk.
 */
int
xfs_log_reserve(xfs_mount_t	 *mp,
		xfs_tid_t	 tid,
		uint		 len,
		xfs_log_ticket_t *x_ticket,
		char		 log_client,
		uint		 flags)
{
	log_t *log = mp->m_log;
	
	if (log_client != XFS_TRANSACTION_MANAGER)
		return -1;
	
	if (flags & XFS_LOG_SLEEP)
		return XFS_ENOTSUP;
	if (flags & XFS_LOG_PERM_RESERV)
		return XFS_ENOTSUP;
	
	/* Eventually force out buffers */
	if (log->l_logreserved + len > log->l_logsize)
		return XFS_ENOLOGSPACE;
	log->l_logreserved += len;
	*x_ticket = (xfs_log_ticket_t) log_maketicket(mp->m_log, tid, len,
						      log_client);
	
	return 0;
}	/* log_reserve */


#ifdef SIM
#include <sys/stat.h>
int
	log_findlogsize(dev_t log_dev)
{
	struct stat buf;
	
	if (fstat(bmajor(log_dev), &buf) == -1)
		return -1;
	
	return buf.st_size;
}
#endif /* SIM */


/*
 * Mount a log filesystem.
 *
 * mp	   -
 * log_dev - device number of on-disk log device
 * flags   -
 *
 */
int
xfs_log_mount(xfs_mount_t	*mp,
	      dev_t		log_dev,
	      uint		flags)
{
	log_t *log;
	
	if ((flags & XFS_LOG_RECOVER) && log_recover(mp, log_dev) != 0) {
		return XFS_ERECOVER;
	}
	log_alloc(mp, log_dev);
	return 0;
}	/* log_mount */


int
xfs_log_unmount(xfs_mount_t *mp)
{
	log_unalloc();
}

int
xfs_log_write(xfs_mount_t *	mp,
	      xfs_log_iovec_t	reg[],
	      int		nentries,
	      xfs_log_ticket_t	tic)
{
	log_write(mp, reg, nentries, tic, 0);
}	/* xfs_log_write */


/*
 * ERRORS:
 *	Return error at any time if reservation is overrun.
 */
int
log_write(xfs_mount_t *		mp,
	  xfs_log_iovec_t	reg[],
	  int			nentries,
	  xfs_log_ticket_t	tic,
	  int			commit)
{
	int len, i, error, log_offset;
	log_ticket_t	*ticket;
	log_op_header_t	logop_head;
	in_core_log_t	*ic_log;
	xfs_lsn_t		lsn;
	log_t		*log = mp->m_log;
	
	for (len=0, i=0; i<nentries; i++) {
		len += reg[i].i_len;
	}
	
	ticket = (log_ticket_t *)tic;
	if (ticket->t_reservation < len) {
		return -1;
	} else {
		ticket->t_reservation -= len;
	}
	
	log_clean(log);
	ic_log		   = log->l_iclog;
	logop_head.oh_tid	   = ticket->t_tid;
	logop_head.oh_clientid = ticket->t_clientid;
	logop_head.oh_len	   = 0;
	if (commit)
		logop_head.oh_flags = LOG_COMMIT;
	else
		logop_head.oh_flags = 0;
	
	
	/* Create log sequence number */
	ASSIGN_LSN(lsn, log->l_cycle, log->l_currblock);
	
	i = 0;
	while (i < nentries) {
	    if ((len + sizeof(log_op_header_t)) < ICLOG_LEFT(ic_log)) {
		if (ticket->t_reservation < sizeof(log_op_header_t)) {
		    return -1;
		} else {
		    ticket->t_reservation -= sizeof(log_op_header_t);
		}
		
		log_offset = ic_log->ic_offset + sizeof(log_op_header_t);
		ic_log->ic_offset += (len + sizeof(log_op_header_t));
		logop_head.oh_len += len;
		bcopy(&logop_head, ic_log->ic_data, sizeof(log_op_header_t));
		
		log_copy(ic_log, reg, i, nentries, log_offset, &lsn);
		log_sync(log, &lsn, XFS_LOG_SYNC);
		return 0;
	    } else {	/* can't fit all regions */
		log_panic("help!");
	    }
	}
}	/* log_write */


void
log_alloc(xfs_mount_t	*mp,
	  dev_t		log_dev)
{
	register log_t		*log;
	log_rec_header_t	*head;
	
	log = mp->m_log = (void *)kmem_zalloc(sizeof(log_t), 0);
	log_alloc_tickets(log);
	
	log->l_dev = log_dev;
	if ((log->l_logsize = log_findlogsize(log_dev)) == -1)
		log_panic("log_findlogsize");
	log->l_logreserved = 0;
	log->l_currblock = 0;
	
	/* Assign 1st in-core log */
	log->l_iclog = (in_core_log_t *)kmem_zalloc(sizeof(in_core_log_t), 0);
	head = &log->l_iclog->ic_header;
	head->h_magicno = LOG_HEADER_MAGIC_NUM;
	head->h_version = 1;
	head->h_lsn = 0;
	log->l_iclog->ic_size = LOG_RECORD_SIZE-LOG_HEADER_SIZE;
	log->l_iclog->ic_state = LOG_CURRENT;
	log->l_iclog->ic_bp = getrbuf(0);
	
	/* Assign backup in-core log */
	log->l_iclog2 = (in_core_log_t *)kmem_zalloc(sizeof(in_core_log_t), 0);
	head = &log->l_iclog2->ic_header;
	head->h_magicno = LOG_HEADER_MAGIC_NUM;
	head->h_version = 1;
	log->l_iclog2->ic_size = LOG_RECORD_SIZE-LOG_HEADER_SIZE;
	log->l_iclog2->ic_state = LOG_NOTUSED;
	log->l_iclog2->ic_bp = getrbuf(0);
}	/* log_alloc */


void
log_unalloc(void)
{
}	/* log_unalloc */


void
log_clean(log_t *log)
{
	switch (log->l_iclog->ic_state) {
		    case LOG_CURRENT: {
			    /* do nothing */
			    break;
		    };
		    case LOG_SYNCING: {
			    log_panic("log_clean: log_sync");
			    break;
		    };
		    case LOG_NOTUSED: {
			    log_panic("log_clean: log_notused");
			    break;
		    };
		    case LOG_DIRTY: {
			    bzero((void *)&log->l_iclog->ic_header, sizeof(log_rec_header_t));
			    break;
		    };
		    default: {
			    log_panic("log_clean: Illegal state");
		    }
	};
}	/* log_clean */



void
log_commit_record(xfs_mount_t  *mp,
		  log_ticket_t *ticket)
{
	int			error;
	xfs_log_iovec_t	reg[1];
	int			nentries = 0;
	
	error = log_write(mp, reg, nentries, ticket, 1);
	if (error)
		log_panic("log_commit_record");
}	/* log_commit_record */


void
log_copy(in_core_log_t	 *iclog,
	 xfs_log_iovec_t reg[],
	 int		 i,
	 int		 n,
	 int		 offset,
	 xfs_lsn_t	 *lsn)
{
	char *ptr = &iclog->ic_data[offset];
	
	iclog->ic_header.h_num_logops++;
	for ( ; i < n; i++) {
		bcopy(reg[i].i_addr, ptr, reg[i].i_len);
		reg[i].i_lsn = *lsn;
		ptr += reg[i].i_len;
	}
}	/* log_copy */


/*
 * purpose: Function which is called when an io completes.  The log manager
 *	needs its own routine, in order to control what happens with the buffer
 *	after the write completes.
 */
void
log_iodone(buf_t *bp)
{
	/* Corresponding psema() will be done in bwrite().  If we don't
	 * vsema() here, panic.
	 */
	if ((bp->b_flags & B_ASYNC) == 0)
		vsema(&bp->b_iodonesema);
}	/* log_iodone */


/*
 * purpose: Flush out the in-core log to the on-disk log in a synchronous or
 *	asynchronous fashion.  The current log to write out should always be
 *	l_iclog.  The two logs are switched, so another thread can begin
 *	writing to the non-syncing in-core log.  Before an in-core log can
 *	be written out, the data section must be scanned to make sure there
 *	are no occurrences of the log header magic number at log block
 *	boundaries.
 */
void
log_sync(log_t		*log,
	 xfs_lsn_t	*lsn,
	 uint		flags)
{
	in_core_log_t	*tic_log = log->l_iclog;
	uint		*dptr;	/* pointer to integer sized element */
	buf_t		*bp;
	int		i = 0;
	uint		count;
	
	if (flags != 0 && ((flags & XFS_LOG_SYNC) != XFS_LOG_SYNC))
		log_panic("log_sync: illegal flag");
	
	/* swap in-core logs */
	log->l_iclog = log->l_iclog2;
	log->l_iclog2 = tic_log;
	tic_log->ic_state = LOG_SYNCING;
	if (log->l_iclog->ic_state == LOG_NOTUSED)
		log->l_iclog->ic_state = LOG_CURRENT;
	
	/* make sure log magic num doesn't fall on 4k log record boundary */
	tic_log->ic_header.h_lsn = *lsn;
	for (dptr = (uint *)tic_log->ic_data + (LOG_BBSIZE - LOG_HEADER_SIZE);
	     dptr < (uint *)tic_log->ic_data + tic_log->ic_offset;
	     dptr += LOG_RECORD_ISIZE) {
		if (*dptr == LOG_HEADER_MAGIC_NUM) {
			tic_log->ic_header.h_blocks_col[i] = ((uint)dptr >> LOG_BBSHIFT);
			*dptr = 0;
			i++;
		}
	}
	tic_log->ic_header.h_len = tic_log->ic_offset;
	
	bp = tic_log->ic_bp;
	bp->b_blkno = LOGBB_TO_BB(log->l_currblock);
	
	/* Round byte count up to a LOG_BBSIZE chunk */
	count = bp->b_bcount = (tic_log->ic_offset + LOG_BBSIZE - 1) & ~LOG_BBMASK;
	bp->b_dmaaddr = (caddr_t) tic_log;
	if (flags & XFS_LOG_SYNC)
		bp->b_flags |= (B_BUSY | B_HOLD);
	else
		bp->b_flags |= (B_BUSY | B_ASYNC);
	bp->b_bufsize = count;
	bp->b_iodone = log_iodone;
	bp->b_edev = log->l_dev;
	psema(&bp->b_lock, PINOD);
	
	bwrite(bp);
	
	if (bp->b_flags & B_ERROR == B_ERROR) {
		log_panic("log_sync: buffer error");
	} else {
		log->l_currblock += NBLOCKS(count);	/* 4k blocks */
	}
	tic_log->ic_state = LOG_DIRTY;
}	/* log_sync */


/*****************************************************************************
 *
 *		TICKET functions
 *
 *****************************************************************************
 */
/*
 *	Algorithm doesn't take into account page size. ;-(
 */
void
log_alloc_tickets(log_t *log)
{
	caddr_t buf;
	log_ticket_t *t_list;
	uint i = LOG_TICKET_TABLE_SIZE-1;

	/*
	 * XXXmiken: may want to account for differing sizes of pointers
	 * or allocation one page at a time.
	 */
	buf = (caddr_t) kmem_zalloc(LOG_TICKET_TABLE_SIZE *
				    sizeof(log_ticket_t), 0);

	t_list = log->l_freelist = (log_ticket_t *)buf;
	do {
		t_list->t_next = t_list+1;
		t_list = t_list->t_next;
	} while (i-- > 0);
	/* t_list->t_slot = 0; => zalloc() did this! */
	t_list->t_next = 0;
}	/* log_alloc_tickets */


/*
 *
 */
void log_putticket(log_t *log,
		   log_ticket_t *ticket)
{
	log_ticket_t *t_list;

	ticket->t_next = log->l_freelist;
	log->l_freelist = ticket;
	/* no need to clear fields */
}	/* log_putticket */


log_ticket_t *
log_maketicket(log_t		*log,
	       xfs_tid_t	tid,
	       int		len,
	       char		log_clientid)
{
	log_ticket_t *tic;

	if (log->l_freelist == NULL) {
		/* do something here */
	}
	tic = log->l_freelist;
	log->l_freelist = tic->t_next;
	tic->t_reservation = len;
	tic->t_tid = tid;
	tic->t_clientid = log_clientid;
	return(tic);
}	/* log_maketicket */


/******************************************************************************
 *
 *		Log recover routines
 *
 ******************************************************************************
 */
uint
xfs_log_end(struct xfs_mount *, dev_t);

int
	log_recover(struct xfs_mount *mp, dev_t log_dev)
{
	return 0;
#if XXXmiken
	blkno = xfs_log_end(mp, log_dev);
	xfs_log_read(blkno, log_dev);
#endif
}

#if XXXmiken
uint
log_end(struct xfs_mount *mp, dev_t log_dev)
{
	struct stat buf;
	int err, log_size, log_blks;
	
	if ((err = fstat(major(log_dev), &buf)) != 0)
		return ERROR;
	
	log_size = buf.st_size;
	log_blks = log_size / 512;
	
}
#endif


/******************************************************************************
 *
 *		Log print routines
 *
 ******************************************************************************
 */

#ifndef _KERNEL
void print_lsn(caddr_t string, xfs_lsn_t *lsn)
{
	printf("%s: %x,%x", string, ((uint *)lsn)[0], ((uint *)lsn)[1]);
}


#if SIM
void print_tid(caddr_t string, xfs_tid_t *tid)
{
	printf("%s: %x", string, ((uint *)tid)[0]);
}
#else
void print_tid(caddr_t string, xfs_tid_t *tid)
{
	printf("%s: %x,%x,%x,%x", string,
	       ((uint *)tid)[0], ((uint *)tid)[1],
	       ((uint *)tid)[2], ((uint *)tid)[3]);
}
#endif

uint log_print_head(log_rec_header_t *head)
{
	uint *uint_ptr;
	
	if (head->h_magicno != LOG_HEADER_MAGIC_NUM) {
		printf("Bad log record header or end of log\n");
		exit(1);
	}
	printf("version: %d	", head->h_version);
	print_lsn("	lsn", &head->h_lsn);
	print_lsn("	sync_lsn", &head->h_sync_lsn);
	printf("\n");
	printf("length of LR: %d	prev offset: %d		num ops: %d\n",
	       head->h_len, head->h_prev_offset, head->h_num_logops);
	uint_ptr = head->h_blocks_col;
	while (uint_ptr) {
		printf("block no: %d\n", uint_ptr);
		uint_ptr++;
	}
	return(head->h_len);
}


void log_print_record(int fd, uint len)
{
	caddr_t buf = (caddr_t) kmem_zalloc(len, 0);
	caddr_t ptr = buf;
	log_op_header_t *head;
	int i = 1, n, read_len;
	
	/* read_len must read up to some block boundary */
	read_len = ((len >> 12) + LOG_BBSIZE-LOG_HEADER_SIZE);
	if (read(fd, buf, read_len) == -1) {
		printf("log_print_record: read error\n");
		exit(1);
	}
	do {
		head = (log_op_header_t *)ptr;
		printf("Operation: %d\n", i);
		print_tid("tid", &head->oh_tid);
		printf("	len: %d	clientid: %s\n",
		       head->oh_len, (head->oh_clientid == XFS_TRANSACTION_MANAGER ?
				      "XFS_TRANSACTION_MANAGER" : "ERROR"));
		ptr += sizeof(log_op_header_t);
		len -= sizeof(log_op_header_t);
		for (n = 0; n < head->oh_len; n++) {
			printf("%c", *ptr);
			ptr++; len--;
		}
		printf("\n");
	} while (len > 0);
}


void xfs_log_print(xfs_mount_t *mp, dev_t log_dev)
{
	int fd = bmajor(log_dev);
	char buf[512];
	int done = 0;
	uint len;
	
	do {
		if ((len=read(fd, buf, 512)) == -1) {
			printf("xfs_log_print end of log\n");
			done++;
			continue;
		}
		len = log_print_head((log_rec_header_t *)buf);
		log_print_record(fd, len);
		printf("=================================\n");
	} while (!done);
}
#endif /* !_KERNEL */






#endif /* LOG_DEBUG */