⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tfs_wcache.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
字号:
#ifndef lintstatic char sccsid[] = "@(#)tfs_wcache.c 1.1 92/07/30 Copyr 1988 Sun Micro";#endif/* * Copyright (c) 1987 Sun Microsystems, Inc. */#include <nse/param.h>#include <nse/util.h>#include "headers.h"#include "tfs.h"#include "vnode.h"#include "subr.h"/* * Routines to maintain a write cache, so that individual tfs_writes of * size less than one block (8K) are bundled together and written as 8K * chunks.  This cache will no longer be necessary when the TFS can have a * UDP buffer size greater than 9K, in which case the write size to the TFS * can be set to 8K.  This cache is necessary for performance in the * meantime because each tfs_write of 2K, say, is flushed from the buffer * cache due to a bug in the NFS client code. * * The write cache sets the mtime of a file to the current time on the local * machine.  Consequently, other routines which set the mtime of a file (e.g. * tfs_create() when no subsequent writes are done, and tfs_setattr() for * truncate) must also use the write cache to ensure that mtimes are always * updated consistently. */#define MAX_CACHE_ELEM	5		/* Max.  # of elements in cache.					 * Should be >= the number of					 * biod's running on the system.					 */#define WRITE_TIMEOUT 5			/* Time that a write buffer allowed					 * to stay in the cache. */#define	BLOCK_MASK	(NFS_MAXDATA - 1)#define ANY_BLOCK	-1typedef struct Write_cache {	struct pnode	*pnode;	long		block;		/* Starting offset of block */	int		offset;		/* Offset within block */	int		count;		/* # of chars in buffer */	char		*buffer;	long		sync_time;	/* When this block should be					 * sync'ed with disk */} *Write_cache, Write_cache_rec;static Write_cache_rec write_cache[MAX_CACHE_ELEM];static int	write_timeout;int		write_wcache();int		read_wcache();bool_t		timeout_wcache();void		sync_entire_wcache();void		sync_wcache();void		flush_wcache();static void	init_wcache();static Write_cache find_unused_wcache_block();static int	write_wcache_block();static void	set_mtime();static Write_cache find_wcache_block();static bool_t	wcache_on;intwrite_wcache(pp, buf, length, offset)	struct pnode	*pp;	char		*buf;	int		length;	long		offset;{	Write_cache	wc;	int		block;	int		block_offset;	if (!wcache_on) {		init_wcache();		wcache_on = TRUE;	}	/*	 * Always make sure that there is an open fd for a file in the	 * write wcache.  (Some routines rely on close_fd() to clean up	 * the write cache.)	 */	if (pp->p_fd == 0 && open_fd(pp, O_RDWR, 0) < 0) {		return (errno);	}	block = (offset & ~BLOCK_MASK);	block_offset = (offset & BLOCK_MASK);	wc = find_wcache_block(pp, block);	if (wc == NULL) {		wc = find_unused_wcache_block();		wc->pnode = pp;		wc->block = block;		wc->offset = block_offset;		/*		 * Note that wc->offset isn't always 0 because		 * find_unused_block() may flush a buffer before it has		 * been completely filled.		 */		wc->count = 0;		wc->sync_time = 0;		pp->p_needs_write = 1;	} else if (block_offset < wc->offset) {		wc->offset = block_offset;	}	if (length > 0) {		BCOPY(buf, wc->buffer + block_offset, length);	}	if (block_offset >= wc->count) {		wc->count += length;	} else {		/*		 * Receiving a write request that is overwriting previous		 * request.  Assuming here that writes arrive sequentially		 * within an 8K block.		 */		wc->count = block_offset + length;	}	pp->p_write_time = get_current_time(TRUE);	if (wc->offset + wc->count == NFS_MAXDATA) {		/*		 * Sync the block with disk immediately if the block is		 * full.		 */		length = write_wcache_block(wc, FALSE);	} else {		wc->sync_time = pp->p_write_time + write_timeout;	}	return (length);}/* * Try to read data from write cache.  Returns -1 if the data is not in the * write cache. */intread_wcache(pp, buf, length, offset)	struct pnode	*pp;	char		*buf;	int		length;	long		offset;{	Write_cache     wc;	int             block;	int		block_offset;	int		len;	block = (offset & ~BLOCK_MASK);	block_offset = (offset & BLOCK_MASK);	wc = find_wcache_block(pp, block);	if (wc == NULL) {		return (-1);	}	if (wc->offset > 0) {		(void) write_wcache_block(wc, TRUE);		return (-1);	}	len = MIN(wc->count - block_offset, length);	BCOPY(wc->buffer + block_offset, buf, len);	return (len);}/* * Called from alarm handler.  Sync's all blocks in the write cache which * have been there too long. */bool_ttimeout_wcache(now)	long		now;{	struct pnode	*pp;	int		i;	bool_t		more_to_sync = FALSE;	if (!wcache_on) {		return (FALSE);	}	for (i = 0; i < MAX_CACHE_ELEM; i++) {		if (write_cache[i].pnode != NULL) {			if (write_cache[i].sync_time < now) {				pp = write_cache[i].pnode;#ifdef TFSDEBUG{	char		pn[MAXPATHLEN];	ptopn(pp, pn);	dprint(tfsdebug, 3, "syncing block %u of %s (sync_time %u)\n",		write_cache[i].block, pn, write_cache[i].sync_time);}#endif TFSDEBUG				(void) write_wcache_block(&write_cache[i],							  TRUE);				if (!pp->p_needs_write && pp->p_fd != 0) {					close_fd(pp);				}			} else {				more_to_sync = TRUE;			}		}	}	return (more_to_sync);}voidsync_entire_wcache(){	int		i;	for (i = 0; i < MAX_CACHE_ELEM; i++) {		if (write_cache[i].pnode != NULL) {			(void) write_wcache_block(&write_cache[i], TRUE);		}	}}/* * Synchronize file 'pp's in-core state with that on disk.  Write out all * blocks for 'pp' which are in the write cache. */voidsync_wcache(pp)	struct pnode	*pp;{	Write_cache	wc;	while ((wc = find_wcache_block(pp, ANY_BLOCK)) != NULL) {		(void) write_wcache_block(wc, TRUE);	}}/* * Flush all blocks for the file with pnode 'pp' from the write cache * (don't write them to the disk.) */voidflush_wcache(pp)	struct pnode	*pp;{	Write_cache	wc;	while ((wc = find_wcache_block(pp, ANY_BLOCK)) != NULL) {		wc->pnode = NULL;	}	pp->p_needs_write = 0;}static voidinit_wcache(){	int		i;	write_timeout = WRITE_TIMEOUT;	for (i = 0; i < MAX_CACHE_ELEM; i++) {		write_cache[i].pnode = NULL;		write_cache[i].buffer = nse_malloc(NFS_MAXDATA);	}}static Write_cachefind_unused_wcache_block(){	static int	block_to_sync;	int		block_num = -1;	int		i;	/*	 * Find an unused wcache block to use, or use one which has an uneven	 * count (a block with (size mod 2K != 0) will probably not receive any	 * more write requests.)	 */	for (i = 0; i < MAX_CACHE_ELEM; i++) {		if (write_cache[i].pnode == NULL) {			block_num = i;			break;		}		if ((write_cache[i].count & 03777) != 0) {			(void) write_wcache_block(&write_cache[i], TRUE);			block_num = i;			break;		}	}	if (block_num == -1) {#ifdef TFSDEBUGdprint(tfsdebug, 3, "find_unused_wcache_block: no buffers free!\n");print_wcache();#endif TFSDEBUG		block_num = block_to_sync;		(void) write_wcache_block(&write_cache[block_to_sync], TRUE);		block_to_sync++;		if (block_to_sync == MAX_CACHE_ELEM) {			block_to_sync = 0;		}	}	return (&write_cache[block_num]);}#ifdef TFSDEBUGprint_wcache(){	Write_cache	wc;	int		i;	for (i = 0; i < MAX_CACHE_ELEM; i++) {		wc = &write_cache[i];		if (wc->pnode != NULL) {			dprint(tfsdebug, 3,				"fd %d  block %d  offset %d  count %d\n",				wc->pnode->p_fd, wc->block, wc->offset,				wc->count);		}	}}#endif TFSDEBUGstatic intwrite_wcache_block(wc, delayed)	Write_cache	wc;	bool_t		delayed;{	struct pnode	*pp;	int		count;	pp = wc->pnode;	if (wc->count > 0) {		count = rdwr_fd(pp, wc->buffer + wc->offset, wc->count,				wc->block + wc->offset, UIO_WRITE);	} else {		count = 0;	}	wc->pnode = NULL;	if (delayed && count == -1) {		pp->p_write_error = errno;		flush_wcache(pp);		return (-1);	}	if (find_wcache_block(pp, ANY_BLOCK) == NULL) {		set_mtime(pp);		pp->p_needs_write = 0;		flush_cached_attrs(pp);	}	return (count);}/* * This routine is called to set the mtime of file 'pp' to the time that * we've given as the mtime in the file's attributes.  This routine is * usually called when write caching causes a delayed write to occur, but * can also be called when there is no data to be written, but the mtime * of the file needs to be updated. */static voidset_mtime(pp)	struct pnode	*pp;{	struct pnode	*parentp;	struct stat	statb;	struct timeval	file_time[2];	char		name[MAXNAMLEN];	int		result;	if (fstat((int) pp->p_fd, &statb) < 0) {		print_warning_msg(pp, "set_mtime: fstat");		return;	}	if (statb.st_mtime == pp->p_write_time) {		return;	}	file_time[0].tv_sec = statb.st_atime;	file_time[0].tv_usec = 0;	file_time[1].tv_sec = pp->p_write_time;	file_time[1].tv_usec = 0;	/*	 * Since close_fd() may call this routine, we can't open any fd's	 * here (we would start recursing between open_fd() and close_fd().)	 * So fchdir to an fd only if one is available.	 */	parentp = PARENT_PNODE(pp);	if (parentp->p_fd != 0 && change_to_dir(parentp) == 0) {		strcpy(name, pp->p_name);	} else {		ptopn(pp, name);	}	result = utimes_as_owner(name, file_time, (int) statb.st_uid);	if (result) {		errno = result;		print_warning_msg(pp, "set_mtime: utimes");	}}/* * Find entry in write cache with pnode 'pp' and block number 'block'.  If * 'block' is ANY_BLOCK, then find any entry for pnode 'pp'. */static Write_cachefind_wcache_block(pp, block)	struct pnode	*pp;	int		block;{	int		i;	for (i = 0; i < MAX_CACHE_ELEM; i++) {		if (write_cache[i].pnode == pp) {			if ((block == ANY_BLOCK) ||			    (write_cache[i].block == block)) {				return (&write_cache[i]);			}		}	}	return (NULL);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -