📄 xpram.c
字号:
/* * Xpram.c -- the S/390 expanded memory RAM-disk * * significant parts of this code are based on * the sbull device driver presented in * A. Rubini: Linux Device Drivers * * Author of XPRAM specific coding: Reinhard Buendgen * buendgen@de.ibm.com * * External interfaces: * Interfaces to linux kernel * xpram_setup: read kernel parameters (see init/main.c) * xpram_init: initialize device driver (see drivers/block/ll_rw_blk.c) * Module interfaces * init_module * cleanup_module * Device specific file operations * xpram_iotcl * xpram_open * xpram_release * * "ad-hoc" partitioning: * the expanded memory can be partitioned among several devices * (with different minors). The partitioning set up can be * set by kernel or module parameters (int devs & int sizes[]) * * module parameters: devs= and sizes= * kernel parameters: xpram_parts= * note: I did not succeed in parsing numbers * for module parameters of type string "s" ?!? * * Other kenel files/modules affected(gerp for "xpram" or "XPRAM": * drivers/s390/Config.in * drivers/s390/block/Makefile * include/linux/blk.h * include/linux/major.h * init/main.c * drivers/block//ll_rw_blk.c * * * Potential future improvements: * request clustering: first coding started not yet tested or integrated * I doubt that it really pays off * generic hard disk support to replace ad-hoc partitioning * * Tested with 2.2.14 (under VM) */#ifdef MODULE# ifndef __KERNEL__# define __KERNEL__# endif# define __NO_VERSION__ /* don't define kernel_version in module.h */#endif /* MODULE */#include <linux/module.h>#include <linux/version.h>#ifdef MODULEchar kernel_version [] = UTS_RELEASE; #endif#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))# define XPRAM_VERSION 24#else# define XPRAM_VERSION 22#endif #if (XPRAM_VERSION == 24)# include <linux/config.h># include <linux/init.h>#endif /* V24 */#include <linux/sched.h>#include <linux/kernel.h> /* printk() */#include <linux/slab.h> /* kmalloc() */#if (XPRAM_VERSION == 24)# include <linux/devfs_fs_kernel.h>#endif /* V24 */#include <linux/fs.h> /* everything... */#include <linux/errno.h> /* error codes */#include <linux/timer.h>#include <linux/types.h> /* size_t */#include <linux/ctype.h> /* isdigit, isxdigit */#include <linux/fcntl.h> /* O_ACCMODE */#include <linux/hdreg.h> /* HDIO_GETGEO */#include <asm/system.h> /* cli(), *_flags */#include <asm/uaccess.h> /* put_user */#if (XPRAM_VERSION == 24)#define MAJOR_NR xpram_major /* force definitions on in blk.h */int xpram_major; /* must be declared before including blk.h */devfs_handle_t xpram_devfs_handle;#define DEVICE_NR(device) MINOR(device) /* xpram has no partition bits */#define DEVICE_NAME "xpram" /* name for messaging */#define DEVICE_INTR xpram_intrptr /* pointer to the bottom half */#define DEVICE_NO_RANDOM /* no entropy to contribute */#define DEVICE_OFF(d) /* do-nothing */#include <linux/blk.h>#include "xpram.h" /* local definitions */__setup("xpram_parts=", xpram_setup);#endif /* V24 *//* define the debug levels: - 0 No debugging output to console or syslog - 1 Log internal errors to syslog, ignore check conditions - 2 Log internal errors and check conditions to syslog - 3 Log internal errors to console, log check conditions to syslog - 4 Log internal errors and check conditions to console - 5 panic on internal errors, log check conditions to console - 6 panic on both, internal errors and check conditions */#define XPRAM_DEBUG 4#define PRINTK_HEADER XPRAM_NAME#if XPRAM_DEBUG > 0#define PRINT_DEBUG(x...) printk ( KERN_DEBUG PRINTK_HEADER "debug:" x )#define PRINT_INFO(x...) printk ( KERN_INFO PRINTK_HEADER "info:" x )#define PRINT_WARN(x...) printk ( KERN_WARNING PRINTK_HEADER "warning:" x )#define PRINT_ERR(x...) printk ( KERN_ERR PRINTK_HEADER "error:" x )#define PRINT_FATAL(x...) panic ( PRINTK_HEADER "panic:"x )#else#define PRINT_DEBUG(x...) printk ( KERN_DEBUG PRINTK_HEADER "debug:" x )#define PRINT_INFO(x...) printk ( KERN_DEBUG PRINTK_HEADER "info:" x )#define PRINT_WARN(x...) printk ( KERN_DEBUG PRINTK_HEADER "warning:" x )#define PRINT_ERR(x...) printk ( KERN_DEBUG PRINTK_HEADER "error:" x )#define PRINT_FATAL(x...) printk ( KERN_DEBUG PRINTK_HEADER "panic:" x )#endif #if (XPRAM_VERSION == 22)#define MAJOR_NR xpram_major /* force definitions on in blk.h */int xpram_major; /* must be declared before including blk.h */#define DEVICE_NR(device) MINOR(device) /* xpram has no partition bits */#define DEVICE_NAME "xpram" /* name for messaging */#define DEVICE_INTR xpram_intrptr /* pointer to the bottom half */#define DEVICE_NO_RANDOM /* no entropy to contribute */#define DEVICE_OFF(d) /* do-nothing */#define DEVICE_REQUEST *xpram_dummy_device_request /* dummy function variable * to prevent warnings */#include <linux/blk.h>#include "xpram.h" /* local definitions */#endif /* V22 *//* * Non-prefixed symbols are static. They are meant to be assigned at * load time. Prefixed symbols are not static, so they can be used in * debugging. They are hidden anyways by register_symtab() unless * XPRAM_DEBUG is defined. */static int major = XPRAM_MAJOR;static int devs = XPRAM_DEVS;static int rahead = XPRAM_RAHEAD;static int sizes[XPRAM_MAX_DEVS] = { 0, };static int blksize = XPRAM_BLKSIZE;static int hardsect = XPRAM_HARDSECT;int xpram_devs, xpram_rahead;int xpram_blksize, xpram_hardsect;int xpram_mem_avail = 0;unsigned long xpram_sizes[XPRAM_MAX_DEVS];MODULE_PARM(devs,"i");MODULE_PARM(sizes,"1-" __MODULE_STRING(XPRAM_MAX_DEVS) "i"); MODULE_PARM_DESC(devs, "number of devices (\"partitions\"), " \ "the default is " __MODULE_STRING(XPRAM_DEVS) "\n");MODULE_PARM_DESC(sizes, "list of device (partition) sizes " \ "the defaults are 0s \n" \ "All devices with size 0 equally partition the " "remaining space on the expanded strorage not " "claimed by explicit sizes\n");/* The following items are obtained through kmalloc() in init_module() */Xpram_Dev *xpram_devices = NULL;int *xpram_blksizes = NULL;int *xpram_hardsects = NULL;int *xpram_offsets = NULL; /* partition offsets */#define MIN(x,y) ((x) < (y) ? (x) : (y))#define MAX(x,y) ((x) > (y) ? (x) : (y))/* * compute nearest multiple of 4 , argument must be non-negative * the macros used depends on XPRAM_KB_IN_PG = 4 */#define NEXT4(x) ((x & 0x3) ? (x+4-(x &0x3)) : (x)) /* increment if needed */#define LAST4(x) ((x & 0x3) ? (x-4+(x & 0x3)) : (x)) /* decrement if needed */#if 0 /* this is probably not faster than the previous code */#define NEXT4(x) ((((x-1)>>2)>>2)+4) /* increment if needed */#define LAST4(x) (((x+3)>>2)<<2) /* decrement if needed */#endif/* integer formats */#define XPRAM_INVALF -1 /* invalid */#define XPRAM_HEXF 0 /* hexadecimal */#define XPRAM_DECF 1 /* decimal *//* * parsing operations (needed for kernel parameter parsing) *//* ------------------------------------------------------------------------- * sets the string pointer after the next comma * * argument: strptr pointer to string * side effect: strptr points to endof string or to position of the next * comma * ------------------------------------------------------------------------*/static voidxpram_scan_to_next_comma (char **strptr){ while ( ((**strptr) != ',') && (**strptr) ) (*strptr)++;}/* ------------------------------------------------------------------------- * interpret character as hex-digit * * argument: c charcter * result: c interpreted as hex-digit * note: can be used to read digits for any base <= 16 * ------------------------------------------------------------------------*/static intxpram_get_hexdigit (char c){ if ((c >= '0') && (c <= '9')) return c - '0'; if ((c >= 'a') && (c <= 'f')) return c + 10 - 'a'; if ((c >= 'A') && (c <= 'F')) return c + 10 - 'A'; return -1;}/*-------------------------------------------------------------------------- * Check format of unsigned integer * * Argument: strptr pointer to string * result: -1 if strptr does not start with a digit * (does not start an integer) * 0 if strptr starts a positive hex-integer with "0x" * 1 if strptr start a positive decimal integer * * side effect: if strptr start a positive hex-integer then strptr is * set to the character after the "0x" *-------------------------------------------------------------------------*/static intxpram_int_format(char **strptr){ if ( !isdigit(**strptr) ) return XPRAM_INVALF; if ( (**strptr == '0') && ( (*((*strptr)+1) == 'x') || (*((*strptr) +1) == 'X') ) && isdigit(*((*strptr)+3)) ) { *strptr=(*strptr)+2; return XPRAM_HEXF; } else return XPRAM_DECF;}/*-------------------------------------------------------------------------- * Read non-negative decimal integer * * Argument: strptr pointer to string starting with a non-negative integer * in decimal format * result: the value of theinitial integer pointed to by strptr * * side effect: strptr is set to the first character following the integer *-------------------------------------------------------------------------*/static intxpram_read_decint (char ** strptr){ int res=0; while ( isdigit(**strptr) ) { res = (res*10) + xpram_get_hexdigit(**strptr); (*strptr)++; } return res;}/*-------------------------------------------------------------------------- * Read non-negative hex-integer * * Argument: strptr pointer to string starting with a non-negative integer * in hexformat (without "0x" prefix) * result: the value of the initial integer pointed to by strptr * * side effect: strptr is set to the first character following the integer *-------------------------------------------------------------------------*/static intxpram_read_hexint (char ** strptr){ int res=0; while ( isxdigit(**strptr) ) { res = (res<<4) + xpram_get_hexdigit(**strptr); (*strptr)++; } return res;}/*-------------------------------------------------------------------------- * Read non-negative integer * * Argument: strptr pointer to string starting with a non-negative integer (either in decimal- or in hex-format * result: the value of the initial integer pointed to by strptr * in case of a parsing error the result is -EINVAL * * side effect: strptr is set to the first character following the integer *-------------------------------------------------------------------------*/static intxpram_read_int (char ** strptr){ switch ( xpram_int_format(strptr) ) { case XPRAM_INVALF: return -EINVAL; case XPRAM_HEXF: return xpram_read_hexint(strptr); case XPRAM_DECF: return xpram_read_decint(strptr); default: return -EINVAL; }}/*-------------------------------------------------------------------------- * Read size * * Argument: strptr pointer to string starting with a non-negative integer * followed optionally by a size modifier: * k or K for kilo (default), * m or M for mega * g or G for giga * result: the value of the initial integer pointed to by strptr * multiplied by the modifier value devided by 1024 * in case of a parsing error the result is -EINVAL * * side effect: strptr is set to the first character following the size *-------------------------------------------------------------------------*/static intxpram_read_size (char ** strptr){ int res; res=xpram_read_int(strptr); if ( res < 0 )return res; switch ( **strptr ) { case 'g': case 'G': res=res*1024; case 'm': case 'M': res=res*1024; case 'k' : case 'K' : (* strptr)++; } return res;}/*-------------------------------------------------------------------------- * Read tail of comma separated size list ",i1,i2,...,in" * * Arguments:strptr pointer to string. It is assumed that the string has * the format (","<size>)* * maxl integer describing the maximal number of elements in the list pointed to by strptr, max must be > 0. * ilist array of dimension >= maxl of integers to be modified * * result: -EINVAL if the list is longer than maxl * 0 otherwise * * side effects: for j=1,...,n ilist[ij] is set to the value of ij if it is * a valid non-negative integer and to -EINVAL otherwise * if no comma is found where it is expected an entry in * ilist is set to -EINVAL *-------------------------------------------------------------------------*/static intxpram_read_size_list_tail (char ** strptr, int maxl, int * ilist){ int i=0; char *str = *strptr; int res=0; while ( (*str == ',') && (i < maxl) ) { str++; ilist[i] = xpram_read_size(&str); if ( ilist[i] == -EINVAL ) { xpram_scan_to_next_comma(&str); res = -EINVAL; } i++; } return res;#if 0 /* be lenient about trailing stuff */ if ( *str != 0 && *str != ' ' ) { ilist[MAX(i-1,0)] = -EINVAL; return -EINVAL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -