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

📄 subr_extent.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*	$NetBSD: subr_extent.c,v 1.39 2000/12/06 18:05:57 thorpej Exp $	*//*- * Copyright (c) 1996, 1998 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe and Matthias Drochner. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the NetBSD *	Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its *    contributors may be used to endorse or promote products derived *    from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. *//* * General purpose extent manager. */#ifdef _KERNEL#include <sys/param.h>#include <sys/extent.h>#include <sys/malloc.h>#include <sys/pool.h>#include <sys/time.h>#include <sys/systm.h>#include <sys/proc.h>#include <sys/lock.h>#include <uvm/uvm_extern.h>#define	KMEM_IS_RUNNING		(kmem_map != NULL)#elif defined(_EXTENT_TESTING)/* * user-land definitions, so it can fit into a testing harness. */#include <sys/param.h>#include <sys/pool.h>#include <sys/extent.h>#include <errno.h>#include <stdlib.h>#include <stdio.h>#include <string.h>/* * Use multi-line #defines to avoid screwing up the kernel tags file; * without this, ctags produces a tags file where panic() shows up * in subr_extent.c rather than subr_prf.c. */#define	\malloc(s, t, flags)		malloc(s)#define	\free(p, t)			free(p)#define	\tsleep(chan, pri, str, timo)	(EWOULDBLOCK)#define	\ltsleep(chan,pri,str,timo,lck)	(EWOULDBLOCK)#define	\wakeup(chan)			((void)0)#define	\pool_get(pool, flags)		malloc(pool->pr_size,0,0)#define	\pool_put(pool, rp)		free(rp,0)#define	\panic(a)			printf(a)#define	\splhigh()			(1)#define	\splx(s)				((void)(s))#define	\simple_lock_init(l)		((void)(l))#define	\simple_lock(l)			((void)(l))#define	\simple_unlock(l)		((void)(l))#define	KMEM_IS_RUNNING			(1)#endifstatic	struct pool *expool_create __P((void));static	void extent_insert_and_optimize __P((struct extent *, u_long, u_long,	    int, struct extent_region *, struct extent_region *));static	struct extent_region *extent_alloc_region_descriptor	    __P((struct extent *, int));static	void extent_free_region_descriptor __P((struct extent *,	    struct extent_region *));static struct pool *expool;/* * Macro to align to an arbitrary power-of-two boundary. */#define EXTENT_ALIGN(_start, _align, _skew)		\	(((((_start) - (_skew)) + ((_align) - 1)) & (-(_align))) + (_skew))/* * Create the extent_region pool. * (This is deferred until one of our callers thinks we can malloc()). */static struct pool *expool_create(){#if defined(_KERNEL)	expool = pool_create(sizeof(struct extent_region), 0, 0,			     0, "extent", 0, 0, 0, 0);#else	expool = (struct pool *)malloc(sizeof(*expool),0,0);	expool->pr_size = sizeof(struct extent_region);#endif	return (expool);}/* * Allocate and initialize an extent map. */struct extent *extent_create(name, start, end, mtype, storage, storagesize, flags)	const char *name;	u_long start, end;	int mtype;	caddr_t storage;	size_t storagesize;	int flags;{	struct extent *ex;	caddr_t cp = storage;	size_t sz = storagesize;	struct extent_region *rp;	int fixed_extent = (storage != NULL);	int s;#ifdef DIAGNOSTIC	/* Check arguments. */	if (name == NULL)		panic("extent_create: name == NULL");	if (end < start) {		printf("extent_create: extent `%s', start 0x%lx, end 0x%lx\n",		    name, start, end);		panic("extent_create: end < start");	}	if (fixed_extent && (storagesize < sizeof(struct extent_fixed)))		panic("extent_create: fixed extent, bad storagesize 0x%lx",		    (u_long)storagesize);	if (fixed_extent == 0 && (storagesize != 0 || storage != NULL))		panic("extent_create: storage provided for non-fixed");#endif	/* Allocate extent descriptor. */	if (fixed_extent) {		struct extent_fixed *fex;		memset(storage, 0, storagesize);		/*		 * Align all descriptors on "long" boundaries.		 */		fex = (struct extent_fixed *)cp;		ex = (struct extent *)fex;		cp += ALIGN(sizeof(struct extent_fixed));		sz -= ALIGN(sizeof(struct extent_fixed));		fex->fex_storage = storage;		fex->fex_storagesize = storagesize;		/*		 * In a fixed extent, we have to pre-allocate region		 * descriptors and place them in the extent's freelist.		 */		LIST_INIT(&fex->fex_freelist);		while (sz >= ALIGN(sizeof(struct extent_region))) {			rp = (struct extent_region *)cp;			cp += ALIGN(sizeof(struct extent_region));			sz -= ALIGN(sizeof(struct extent_region));			LIST_INSERT_HEAD(&fex->fex_freelist, rp, er_link);		}	} else {		s = splhigh();		if (expool == NULL)			expool_create();		splx(s);		if (expool == NULL)			return (NULL);		ex = (struct extent *)malloc(sizeof(struct extent),		    mtype, (flags & EX_WAITOK) ? M_WAITOK : M_NOWAIT);		if (ex == NULL)			return (NULL);	}	/* Fill in the extent descriptor and return it to the caller. */	simple_lock_init(&ex->ex_slock);	LIST_INIT(&ex->ex_regions);	ex->ex_name = name;	ex->ex_start = start;	ex->ex_end = end;	ex->ex_mtype = mtype;	ex->ex_flags = 0;	if (fixed_extent)		ex->ex_flags |= EXF_FIXED;	if (flags & EX_NOCOALESCE)		ex->ex_flags |= EXF_NOCOALESCE;	return (ex);}/* * Destroy an extent map. * Since we're freeing the data, there can't be any references * so we don't need any locking. */voidextent_destroy(ex)	struct extent *ex;{	struct extent_region *rp, *orp;#ifdef DIAGNOSTIC	/* Check arguments. */	if (ex == NULL)		panic("extent_destroy: NULL extent");#endif	/* Free all region descriptors in extent. */	for (rp = ex->ex_regions.lh_first; rp != NULL; ) {		orp = rp;		rp = rp->er_link.le_next;		LIST_REMOVE(orp, er_link);		extent_free_region_descriptor(ex, orp);	}	/* If we're not a fixed extent, free the extent descriptor itself. */	if ((ex->ex_flags & EXF_FIXED) == 0)		free(ex, ex->ex_mtype);}/* * Insert a region descriptor into the sorted region list after the * entry "after" or at the head of the list (if "after" is NULL). * The region descriptor we insert is passed in "rp".  We must * allocate the region descriptor before calling this function! * If we don't need the region descriptor, it will be freed here. */static voidextent_insert_and_optimize(ex, start, size, flags, after, rp)	struct extent *ex;	u_long start, size;	int flags;	struct extent_region *after, *rp;{	struct extent_region *nextr;	int appended = 0;	if (after == NULL) {		/*		 * We're the first in the region list.  If there's		 * a region after us, attempt to coalesce to save		 * descriptor overhead.		 */		if (((ex->ex_flags & EXF_NOCOALESCE) == 0) &&		    (ex->ex_regions.lh_first != NULL) &&		    ((start + size) == ex->ex_regions.lh_first->er_start)) {			/*			 * We can coalesce.  Prepend us to the first region.			 */			ex->ex_regions.lh_first->er_start = start;			extent_free_region_descriptor(ex, rp);			return;		}		/*		 * Can't coalesce.  Fill in the region descriptor		 * in, and insert us at the head of the region list.		 */		rp->er_start = start;		rp->er_end = start + (size - 1);		LIST_INSERT_HEAD(&ex->ex_regions, rp, er_link);		return;	}	/*	 * If EXF_NOCOALESCE is set, coalescing is disallowed.	 */	if (ex->ex_flags & EXF_NOCOALESCE)		goto cant_coalesce;	/*	 * Attempt to coalesce with the region before us.	 */	if ((after->er_end + 1) == start) {		/*		 * We can coalesce.  Append ourselves and make		 * note of it.		 */		after->er_end = start + (size - 1);		appended = 1;	}	/*	 * Attempt to coalesce with the region after us.	 */	if ((after->er_link.le_next != NULL) &&	    ((start + size) == after->er_link.le_next->er_start)) {		/*		 * We can coalesce.  Note that if we appended ourselves		 * to the previous region, we exactly fit the gap, and		 * can free the "next" region descriptor.		 */		if (appended) {			/*			 * Yup, we can free it up.			 */			after->er_end = after->er_link.le_next->er_end;			nextr = after->er_link.le_next;			LIST_REMOVE(nextr, er_link);			extent_free_region_descriptor(ex, nextr);		} else {			/*			 * Nope, just prepend us to the next region.			 */			after->er_link.le_next->er_start = start;		}		extent_free_region_descriptor(ex, rp);		return;	}	/*	 * We weren't able to coalesce with the next region, but	 * we don't need to allocate a region descriptor if we	 * appended ourselves to the previous region.	 */	if (appended) {		extent_free_region_descriptor(ex, rp);		return;	} cant_coalesce:	/*	 * Fill in the region descriptor and insert ourselves	 * into the region list.	 */	rp->er_start = start;	rp->er_end = start + (size - 1);	LIST_INSERT_AFTER(after, rp, er_link);}/* * Allocate a specific region in an extent map. */intextent_alloc_region(ex, start, size, flags)	struct extent *ex;	u_long start, size;	int flags;{	struct extent_region *rp, *last, *myrp;	u_long end = start + (size - 1);	int error;#ifdef DIAGNOSTIC	/* Check arguments. */	if (ex == NULL)		panic("extent_alloc_region: NULL extent");	if (size < 1) {		printf("extent_alloc_region: extent `%s', size 0x%lx\n",		    ex->ex_name, size);		panic("extent_alloc_region: bad size");	}	if (end < start) {		printf(		 "extent_alloc_region: extent `%s', start 0x%lx, size 0x%lx\n",		 ex->ex_name, start, size);		panic("extent_alloc_region: overflow");	}#endif	/*	 * Make sure the requested region lies within the	 * extent.	 *	 * We don't lock to check the range, because those values	 * are never modified, and if another thread deletes the	 * extent, we're screwed anyway.	 */	if ((start < ex->ex_start) || (end > ex->ex_end)) {#ifdef DIAGNOSTIC		printf("extent_alloc_region: extent `%s' (0x%lx - 0x%lx)\n",		    ex->ex_name, ex->ex_start, ex->ex_end);		printf("extent_alloc_region: start 0x%lx, end 0x%lx\n",		    start, end);		panic("extent_alloc_region: region lies outside extent");#else		return (EINVAL);#endif	}	/*	 * Allocate the region descriptor.  It will be freed later	 * if we can coalesce with another region.  Don't lock before	 * here!  This could block.	 */	myrp = extent_alloc_region_descriptor(ex, flags);	if (myrp == NULL) {#ifdef DIAGNOSTIC		printf(		    "extent_alloc_region: can't allocate region descriptor\n");#endif		return (ENOMEM);	} alloc_start:	simple_lock(&ex->ex_slock);	/*	 * Attempt to place ourselves in the desired area of the	 * extent.  We save ourselves some work by keeping the list sorted.	 * In other words, if the start of the current region is greater	 * than the end of our region, we don't have to search any further.	 */	/*	 * Keep a pointer to the last region we looked at so	 * that we don't have to traverse the list again when	 * we insert ourselves.  If "last" is NULL when we	 * finally insert ourselves, we go at the head of the	 * list.  See extent_insert_and_optimize() for details.	 */	last = NULL;	for (rp = ex->ex_regions.lh_first; rp != NULL;	    rp = rp->er_link.le_next) {		if (rp->er_start > end) {			/*			 * We lie before this region and don't			 * conflict.			 */			break;		}		/*		 * The current region begins before we end.		 * Check for a conflict.		 */		if (rp->er_end >= start) {			/*			 * We conflict.  If we can (and want to) wait,			 * do so.			 */			if (flags & EX_WAITSPACE) {				ex->ex_flags |= EXF_WANTED;				error = ltsleep(ex,				    PNORELOCK | PRIBIO | ((flags & EX_CATCH) ? PCATCH : 0),				    "extnt", 0, &ex->ex_slock);				if (error)					return (error);				goto alloc_start;			}			extent_free_region_descriptor(ex, myrp);			simple_unlock(&ex->ex_slock);			return (EAGAIN);		}		/*		 * We don't conflict, but this region lies before		 * us.  Keep a pointer to this region, and keep		 * trying.		 */		last = rp;	}	/*	 * We don't conflict with any regions.  "last" points	 * to the region we fall after, or is NULL if we belong	 * at the beginning of the region list.  Insert ourselves.	 */	extent_insert_and_optimize(ex, start, size, flags, last, myrp);	simple_unlock(&ex->ex_slock);	return (0);}/* * Macro to check (x + y) <= z.  This check is designed to fail * if an overflow occurs. */#define LE_OV(x, y, z)	((((x) + (y)) >= (x)) && (((x) + (y)) <= (z)))/* * Allocate a region in an extent map subregion. * * If EX_FAST is specified, we return the first fit in the map. * Otherwise, we try to minimize fragmentation by finding the * smallest gap that will hold the request. * * The allocated region is aligned to "alignment", which must be * a power of 2. */intextent_alloc_subregion1(ex, substart, subend, size, alignment, skew, boundary,    flags, result)	struct extent *ex;	u_long substart, subend, size, alignment, skew, boundary;	int flags;	u_long *result;{	struct extent_region *rp, *myrp, *last, *bestlast;	u_long newstart, newend, beststart, bestovh, ovh;	u_long dontcross;	int error;#ifdef DIAGNOSTIC	/*	 * Check arguments.	 *	 * We don't lock to check these, because these values	 * are never modified, and if another thread deletes the	 * extent, we're screwed anyway.	 */	if (ex == NULL)		panic("extent_alloc_subregion: NULL extent");	if (result == NULL)		panic("extent_alloc_subregion: NULL result pointer");	if ((substart < ex->ex_start) || (substart > ex->ex_end) ||	    (subend > ex->ex_end) || (subend < ex->ex_start)) {  printf("extent_alloc_subregion: extent `%s', ex_start 0x%lx, ex_end 0x%lx\n",		    ex->ex_name, ex->ex_start, ex->ex_end);		printf("extent_alloc_subregion: substart 0x%lx, subend 0x%lx\n",		    substart, subend);		panic("extent_alloc_subregion: bad subregion");	}	if ((size < 1) || ((size - 1) > (subend - substart))) {		printf("extent_alloc_subregion: extent `%s', size 0x%lx\n",		    ex->ex_name, size);		panic("extent_alloc_subregion: bad size");	}	if (alignment == 0)		panic("extent_alloc_subregion: bad alignment");	if (boundary && (boundary < size)) {		printf(		    "extent_alloc_subregion: extent `%s', size 0x%lx,		    boundary 0x%lx\n", ex->ex_name, size, boundary);		panic("extent_alloc_subregion: bad boundary");	}#endif	/*	 * Allocate the region descriptor.  It will be freed later	 * if we can coalesce with another region.  Don't lock before	 * here!  This could block.	 */	myrp = extent_alloc_region_descriptor(ex, flags);	if (myrp == NULL) {#ifdef DIAGNOSTIC		printf(		 "extent_alloc_subregion: can't allocate region descriptor\n");#endif		return (ENOMEM);	} alloc_start:	simple_lock(&ex->ex_slock);	/*	 * Keep a pointer to the last region we looked at so	 * that we don't have to traverse the list again when	 * we insert ourselves.  If "last" is NULL when we

⌨️ 快捷键说明

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