[PATCH] ramdisk for unusable memory > 960MB / > 2 GB

Manfred Spraul (masp0008@stud.uni-sb.de)
Mon, 01 Feb 1999 11:26:10 +0100


This is a multi-part message in MIME format.
--------------1D464FE45E61A46C49E47F84
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

This patch adds:
- 2 new kernel functions (alloc_hugemem, free_hugemem) that manage
physical, unmapped memory. (Note: if you have 1 GB memory, then there is
usually 64 MB unused memory).
- a special ramdisk that uses this memory. ( MAJOR=126, MINOR=0..7)

Remarks:
- the patch is BETA. I've tested the patch with 12 MB memory, 50 MB
RAM-Swapdisk.
- It should work on SMP, but I can't test that.
- The ramdisk currently does not compile as a module
- The patch only applies to the __i386__ platform
- I've attached a simple setup program for the new ramdisk

Regards,
Manfred
--------------1D464FE45E61A46C49E47F84
Content-Type: text/plain; charset=us-ascii; name="patch.beta1"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="patch.beta1"

Only in old: .config
diff -u -r -P old/Documentation/Configure.help new/Documentation/Configure.help
--- old/Documentation/Configure.help Mon Feb 1 09:56:02 1999
+++ new/Documentation/Configure.help Mon Feb 1 10:35:13 1999
@@ -229,6 +229,18 @@

Most users will answer N here.

+Hugeram Ramdisk
+CONFIG_BLK_DEV_HUGERAMD
+ Saying Y here makes it possible to use the memory above 1 gigabyte
+ as a ramdisk. This only works if you have enabled CONFIG_HUGEMEM.
+
+ If you want to compile this driver as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want),
+ say M here and read Documentation/modules.txt. The module will be
+ called hugeramd.o.
+
+ Most users will answer N here.
+
Network Block Device support
CONFIG_BLK_DEV_NBD
Saying Y here will allow your computer to be a client for network
@@ -8367,6 +8379,14 @@

See Documentation/mtrr.txt for more information.

+Huge memory support
+CONFIG_HUGEMEM
+ Enables kernel support for more than 2 gigabyte physical memory.
+ Note that this memory is only used for special devices such as
+ hugeramd.
+
+ If unsure, say 'N'.
+
Main CPU frequency, only for DEC alpha machine
CONFIG_FT_ALPHA_CLOCK
On some DEC Alpha machines the CPU clock frequency cannot be
diff -u -r -P old/arch/i386/config.in new/arch/i386/config.in
--- old/arch/i386/config.in Mon Feb 1 10:32:14 1999
+++ new/arch/i386/config.in Mon Feb 1 10:35:13 1999
@@ -36,6 +36,7 @@
bool 'Math emulation' CONFIG_MATH_EMULATION
bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR
bool 'Symmetric multi-processing support' CONFIG_SMP
+bool 'Huge memory support' CONFIG_HUGEMEM
endmenu

mainmenu_option next_comment
diff -u -r -P old/arch/i386/kernel/Makefile new/arch/i386/kernel/Makefile
--- old/arch/i386/kernel/Makefile Mon Feb 1 09:55:46 1999
+++ new/arch/i386/kernel/Makefile Mon Feb 1 10:35:13 1999
@@ -26,6 +26,10 @@
O_OBJS += mca.o
endif

+ifdef CONFIG_HUGEMEM
+O_OBJS += hugemem.o
+endif
+
ifeq ($(CONFIG_MTRR),y)
OX_OBJS += mtrr.o
else
diff -u -r -P old/arch/i386/kernel/hugemem.c new/arch/i386/kernel/hugemem.c
--- old/arch/i386/kernel/hugemem.c Thu Jan 1 01:00:00 1970
+++ new/arch/i386/kernel/hugemem.c Mon Feb 1 10:46:26 1999
@@ -0,0 +1,129 @@
+/*
+ * linux/arch/i386/kernel/hugemem.c
+ *
+ * Copyright 1999 by Manfred Spraul <masp0008@stud.uni-sb.de>
+ */
+
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/sched.h>
+#include <linux/hugemem.h>
+#include <asm/spinlock.h>
+
+/*
+ global variables:
+ */
+
+int hugemem_startpg; /* number of the first page managed by hugemem */
+int hugemem_len = 0;
+unsigned char* hugemem_bitmap = NULL;
+
+spinlock_t hugemem_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ internal functions:
+ */
+
+int hm_init(void);
+
+/* public interface for modules. */
+EXPORT_SYMBOL(alloc_hugemem);
+EXPORT_SYMBOL(free_hugemem);
+
+/*
+ This function is called very early, it cannot call
+ any other kernel function.
+ Defer the actual initialization.
+ */
+
+void init_hugemem(int memstart, int memend)
+{
+ memstart = (memstart + PAGE_SIZE-1) & PAGE_MASK;
+ memend = memend & PAGE_MASK;
+
+ hugemem_startpg = memstart/PAGE_SIZE;
+ hugemem_len = (memend-memstart)/PAGE_SIZE/HM_PAGES_PER_BIT;
+}
+
+int alloc_hugemem(int size)
+{
+ int result;
+ int i, missing;
+
+ if(hugemem_len == 0)
+ return -1;
+
+ if(size == 0)
+ return -1;
+
+ spin_lock(hugemem_lock);
+
+ if(hugemem_bitmap == NULL) {
+ if(!hm_init()) {
+ spin_unlock(hugemem_lock);
+ return -1;
+ }
+ }
+
+ size = (size+HM_PAGES_PER_BIT-1)/HM_PAGES_PER_BIT;
+
+ result = -1;
+ missing = size;
+ for(i=0;i<hugemem_len;i++) {
+ if( (hugemem_bitmap[i/8] & (0x80>>(i&0x07))) == 0) {
+ if(result==-1) {
+ missing = size;
+ result = i;
+ }
+ missing--;
+ if(missing == 0)
+ break;
+ } else {
+ result = -1;
+ }
+ }
+ if(missing != 0)
+ {
+ spin_unlock(hugemem_lock);
+ return -1;
+ }
+ for(i=result;i<result+size;i++)
+ hugemem_bitmap[i/8] |= 0x80>>(i&0x07);
+
+ spin_unlock(hugemem_lock);
+ return result*HM_PAGES_PER_BIT+hugemem_startpg;
+}
+
+void free_hugemem(int startpg, int size)
+{
+ startpg -= hugemem_startpg;
+ size = (size+HM_PAGES_PER_BIT-1)/HM_PAGES_PER_BIT;
+
+ if((size > hugemem_len) || (size==0) || (startpg&(HM_PAGES_PER_BIT-1))) {
+ printk(KERN_DEBUG "free_hugemem: invalid parameter.");
+ return;
+ }
+ if(hugemem_bitmap == NULL)
+ return;
+
+ spin_lock(hugemem_lock);
+
+ startpg /= HM_PAGES_PER_BIT;
+ while(size != 0) {
+ hugemem_bitmap[startpg/8] &= ~(0x80>>(startpg & 0x07));
+ startpg++;
+ size--;
+ }
+ spin_unlock(hugemem_lock);
+ return;
+}
+
+int hm_init(void)
+{
+ hugemem_bitmap = kmalloc((hugemem_len+7)/8,GFP_ATOMIC);
+ if(hugemem_bitmap == NULL)
+ return 0;
+ memset(hugemem_bitmap,0,(hugemem_len+7)/8);
+ return 1;
+}
+
diff -u -r -P old/arch/i386/kernel/setup.c new/arch/i386/kernel/setup.c
--- old/arch/i386/kernel/setup.c Mon Feb 1 09:55:46 1999
+++ new/arch/i386/kernel/setup.c Mon Feb 1 10:43:41 1999
@@ -32,6 +32,9 @@
#ifdef CONFIG_BLK_DEV_RAM
#include <linux/blk.h>
#endif
+#ifdef CONFIG_HUGEMEM
+#include <linux/hugemem.h>
+#endif
#include <asm/processor.h>
#include <linux/console.h>
#include <asm/uaccess.h>
@@ -332,6 +335,9 @@

if (memory_end > MAXMEM)
{
+#ifdef CONFIG_HUGEMEM
+ init_hugemem(MAXMEM,memory_end);
+#endif
memory_end = MAXMEM;
printk(KERN_WARNING "Warning only %ldMB will be used.\n",
MAXMEM>>20);
diff -u -r -P old/drivers/block/Config.in new/drivers/block/Config.in
--- old/drivers/block/Config.in Mon Feb 1 09:55:27 1999
+++ new/drivers/block/Config.in Mon Feb 1 10:35:13 1999
@@ -94,6 +94,7 @@
comment 'Additional Block Devices'

tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
+tristate 'Hugeram Ramdisk' CONFIG_BLK_DEV_HUGERAMD
if [ "$CONFIG_NET" = "y" ]; then
tristate 'Network block device support' CONFIG_BLK_DEV_NBD
fi
diff -u -r -P old/drivers/block/Makefile new/drivers/block/Makefile
--- old/drivers/block/Makefile Mon Feb 1 09:55:27 1999
+++ new/drivers/block/Makefile Mon Feb 1 10:35:13 1999
@@ -94,6 +94,14 @@
endif
endif

+ifeq ($(CONFIG_BLK_DEV_HUGERAMD),y)
+L_OBJS += hugeramd.o
+else
+ ifeq ($(CONFIG_BLK_DEV_HUGERAMD),m)
+ M_OBJS += hugeramd.o
+ endif
+endif
+
ifeq ($(CONFIG_BLK_DEV_HD),y)
L_OBJS += hd.o
endif
diff -u -r -P old/drivers/block/hugeramd.c new/drivers/block/hugeramd.c
--- old/drivers/block/hugeramd.c Thu Jan 1 01:00:00 1970
+++ new/drivers/block/hugeramd.c Mon Feb 1 10:40:41 1999
@@ -0,0 +1,312 @@
+/*
+ * linux/drivers/block/hugeramd.c
+ *
+ * Written by Manfred Spraul
+ *
+ * based on the loop driver written by Theodore Ts'o
+ */
+
+#include <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/ioctl.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/errno.h>
+#include <linux/major.h>
+#include <linux/hugeramd.h>
+#include <linux/hugemem.h>
+
+#define MAJOR_NR HUGERAMD_MAJOR
+#define DEVICE_NAME "HugeRamD"
+#define DEVICE_NR(device) MINOR(device)
+#define DEVICE_NO_RANDOM
+#define DEVICE_OFF(x) do { } while (0)
+#define DEVICE_REQUEST hugeramd_request
+#include <linux/blk.h>
+
+struct HRD_DEVICE {
+ spinlock_t lock;
+ void* remap_addr;
+ int start; /* in pages */
+ int size;
+ int refcount;
+} ;
+
+
+struct HRD_DEVICE hrd_devices[MAX_HUGERAMD];
+
+int hugeramd_bps[MAX_HUGERAMD] = { 0};
+int hugeramd_blockcount[MAX_HUGERAMD] = {0};
+#define FALSE 0
+#define TRUE (!FALSE)
+
+/*
+ internal prototypes
+*/
+
+int hrd_rw(int dev, unsigned long offset, char* buf, int len, int read);
+
+static int hrd_ioctl(struct inode * inode, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct HRD_DEVICE* hrd;
+ int dev;
+ int res;
+
+ if (!inode)
+ return -EINVAL;
+ if (MAJOR(inode->i_rdev) != HUGERAMD_MAJOR) {
+ printk(KERN_WARNING "hrd_ioctl: pseudo-major != %d\n", HUGERAMD_MAJOR);
+ return -ENODEV;
+ }
+ dev = MINOR(inode->i_rdev);
+ if (dev >= MAX_HUGERAMD)
+ return -ENODEV;
+ hrd = &hrd_devices[dev];
+ spin_lock(hrd->lock);
+ res = 0;
+ switch (cmd) {
+ case BLKGETSIZE: /* Return device size */
+ res = put_user(hrd->size<<3, (long *) arg);
+ break;
+ case HRDSETBPS:
+ if(!capable(CAP_SYS_ADMIN)) {
+ res = -EACCES;
+ break;
+ }
+ if( (arg != 512) &&
+ (arg != 1024) &&
+ (arg != 2048) &&
+ (arg != 4096) ) {
+ res = -EINVAL;
+ break;
+ }
+ hugeramd_bps[dev] = arg;
+ hugeramd_blockcount[dev] = hrd->size*(PAGE_SIZE/hugeramd_bps[dev]);
+ break;
+ case HRDSETSIZE:
+ if(!capable(CAP_SYS_ADMIN)) {
+ res = -EACCES;
+ break;
+ }
+ if(hrd->size != 0)
+ {
+ free_hugemem(hrd->start,
+ hrd->size);
+ hrd->size = 0;
+ }
+ if(arg == 0)
+ break;
+ hrd->start = alloc_hugemem(arg);
+ if(hrd->start == -1) {
+ res = -ENOMEM;
+ break;
+ }
+ hrd->size = arg;
+
+ hrd->remap_addr = ioremap(hrd->start*PAGE_SIZE, PAGE_SIZE);
+ if(hrd->remap_addr == NULL) {
+ free_hugemem(hrd->start,
+ hrd->size);
+ res = -ENOMEM;
+ break;
+ }
+ hugeramd_blockcount[dev] = hrd->size*(PAGE_SIZE/hugeramd_bps[dev]);
+ break;
+
+ /* FIXME: additional ioctl's required? */
+ default:
+ res = -EINVAL;
+ }
+ spin_unlock(hrd->lock);
+ return res;
+}
+
+static int hrd_open(struct inode *inode, struct file *file)
+{
+ struct HRD_DEVICE *hrd;
+ int dev;
+
+ if (!inode)
+ return -EINVAL;
+ if (MAJOR(inode->i_rdev) != HUGERAMD_MAJOR) {
+ printk(KERN_WARNING "hrd_open: pseudo-major != %d\n", HUGERAMD_MAJOR);
+ return -ENODEV;
+ }
+ dev = MINOR(inode->i_rdev);
+ if (dev >= MAX_HUGERAMD) {
+ return -ENODEV;
+ }
+ hrd = &hrd_devices[dev];
+
+ spin_lock(hrd->lock);
+ hrd->refcount++;
+ spin_unlock(hrd->lock);
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int hrd_release(struct inode *inode, struct file *file)
+{
+ struct HRD_DEVICE* hrd;
+ int dev;
+
+ if (!inode)
+ return 0;
+ if (MAJOR(inode->i_rdev) != HUGERAMD_MAJOR) {
+ printk(KERN_WARNING "hrd_release: pseudo-major != %d\n", HUGERAMD_MAJOR);
+ return 0;
+ }
+ dev = MINOR(inode->i_rdev);
+ if (dev >= MAX_HUGERAMD)
+ return 0;
+ hrd = &hrd_devices[dev];
+ spin_lock(hrd->lock);
+
+ if (hrd->refcount <= 0)
+ printk(KERN_ERR "hrd_release: refcount(MINOR=%d) <= 0\n", dev);
+ else {
+ hrd->refcount--;
+ if(hrd->refcount == 0)
+ MOD_DEC_USE_COUNT;
+ }
+ spin_unlock(hrd->lock);
+ return 0;
+}
+
+int hrd_fsync(struct file* unused, struct dentry* unused2)
+{
+ /* syncing a ramdisk??? */
+ return 0;
+}
+
+void hugeramd_request(void)
+{
+ int dev;
+ int res;
+
+ while(1) {
+ INIT_REQUEST
+
+ dev = DEVICE_NR(CURRENT->rq_dev);
+ if(dev > MAX_HUGERAMD) {
+ end_request(0);
+ } else
+ {
+ spin_lock(hrd_devices[dev].spinlock);
+ res = hrd_rw(dev, CURRENT->sector, CURRENT->buffer, CURRENT->current_nr_sectors, (CURRENT->cmd != WRITE) );
+ spin_unlock(hrd_devices[dev].spinlock);
+ end_request(res);
+ }
+ }
+}
+
+static struct file_operations hrd_fops = {
+ NULL, /* lseek - default */
+ block_read, /* read */
+ block_write, /* write */
+ NULL, /* readdir - bad */
+ NULL, /* poll */
+ hrd_ioctl, /* ioctl */
+ NULL, /* mmap */
+ hrd_open, /* open */
+ NULL, /* flush */
+ hrd_release, /* release */
+ block_fsync /* fsync */
+};
+
+/*
+ * And now the modules code and kernel interface.
+ */
+#ifdef MODULE
+#define hugeramd_init init_module
+#endif
+
+int hugeramd_init(void)
+{
+ int i;
+
+ if (register_blkdev(HUGERAMD_MAJOR, "hugeramd", &hrd_fops)) {
+ printk(KERN_WARNING "Unable to get major number %d for hugeramd device\n",
+ HUGERAMD_MAJOR);
+ return -EIO;
+ }
+#ifndef MODULE
+ printk(KERN_INFO "hugeramd: registered device at major %d\n", HUGERAMD_MAJOR);
+#endif
+ /* FIXME: which global variables must be initialized? */
+
+ blksize_size[HUGERAMD_MAJOR] = hugeramd_bps;
+ blk_size[HUGERAMD_MAJOR] = hugeramd_blockcount;
+ read_ahead[HUGERAMD_MAJOR] = 0; /* no read ahead, since the seek time is 0 */
+ hardsect_size[HUGERAMD_MAJOR] = NULL;
+ blk_dev[HUGERAMD_MAJOR].request_fn = DEVICE_REQUEST;
+
+ for (i=0; i < MAX_HUGERAMD; i++) {
+ memset(&hrd_devices[i],0,sizeof(hrd_devices[i]));
+ hrd_devices[i].lock = SPIN_LOCK_UNLOCKED;
+ hugeramd_bps[i] = 1024;
+ hugeramd_blockcount[i] = 0;
+ }
+ return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+ if (unregister_blkdev(HUGERAMD_MAJOR, "hugeramd") != 0)
+ printk(KERN_WARNING "hugeramd: cannot unregister blkdev\n");
+}
+#endif
+
+int hrd_rw(int dev, unsigned long offset, char* buf, int len, int read)
+{
+ struct HRD_DEVICE* hrd = &hrd_devices[dev];
+ loff_t byteoff = offset*512;
+
+
+ len *= 512;
+ if(byteoff > ((loff_t)hrd->size)*PAGE_SIZE)
+ return 0;
+ if(byteoff+len > ((loff_t)hrd->size)*PAGE_SIZE)
+ len = ((loff_t)hrd->size)*PAGE_SIZE-byteoff;
+
+ while(len != 0) {
+ unsigned long linear = (unsigned long)hrd->remap_addr;
+ pte_t* pte = pte_offset(pmd_offset(pgd_offset_k(linear),linear), linear);
+ unsigned long physoffset;
+ int datalen;
+ int offset;
+
+ physoffset = hrd->start + (byteoff>>PAGE_SHIFT);
+ physoffset *= PAGE_SIZE;
+ offset = byteoff & (PAGE_SIZE-1);
+
+ set_pte(pte, mk_pte_phys(physoffset, __pgprot(_PAGE_PRESENT| _PAGE_RW |
+ _PAGE_DIRTY | _PAGE_ACCESSED )));
+
+ /* this call only affects the current cpu.
+ This is not a problem, because only one cpu is allowed to execute
+ these lines.
+ */
+ __flush_tlb_one(linear);
+
+ datalen = PAGE_SIZE-offset;
+
+ if(datalen > len)
+ datalen = len;
+
+ if(read)
+ memcpy(buf,(char*)linear+offset,datalen);
+ else
+ memcpy((char*)linear+offset, buf, datalen);
+
+ buf += datalen;
+ len -= datalen;
+ byteoff += datalen;
+ }
+
+ return 1;
+}
diff -u -r -P old/drivers/block/ll_rw_blk.c new/drivers/block/ll_rw_blk.c
--- old/drivers/block/ll_rw_blk.c Mon Feb 1 09:55:27 1999
+++ new/drivers/block/ll_rw_blk.c Mon Feb 1 10:41:18 1999
@@ -740,6 +739,9 @@
#ifdef CONFIG_BLK_DEV_RAM
rd_init();
#endif
+#ifdef CONFIG_BLK_DEV_HUGERAMD
+ hugeramd_init();
+#endif
#ifdef CONFIG_BLK_DEV_LOOP
loop_init();
#endif
diff -u -r -P old/include/linux/blk.h new/include/linux/blk.h
--- old/include/linux/blk.h Mon Feb 1 09:55:12 1999
+++ new/include/linux/blk.h Mon Feb 1 10:35:13 1999
@@ -52,6 +52,7 @@
extern int xd_init(void);
extern int mfm_init(void);
extern int loop_init(void);
+extern int hugeramd_init(void);
extern int md_init(void);
extern int ap_init(void);
extern int ddv_init(void);
diff -u -r -P old/include/linux/hugemem.h new/include/linux/hugemem.h
--- old/include/linux/hugemem.h Thu Jan 1 01:00:00 1970
+++ new/include/linux/hugemem.h Mon Feb 1 10:35:13 1999
@@ -0,0 +1,47 @@
+/*
+ * Huge memory support
+ *
+ * Copyright 1999 by Manfred Spraul <masp0008@stud.uni-sb.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ */
+#ifndef _HUGEMEM_H
+#define _HUGEMEM_H
+
+#ifndef __i386__
+#error Hugemem is only supported on the i386 platform.
+#endif
+
+
+void init_hugemem(int memstart, int memend);
+
+/*
+ All size parameters are page counts.
+
+ hugemem internally rounds all allocation
+ to this size. Use kmalloc if you need less
+ memory
+ */
+
+#define HM_PAGES_PER_BIT 64
+
+/* return value: start of the physical area, or 0 on error. */
+int alloc_hugemem(int size);
+
+void free_hugemem(int startpg, int size);
+
+#endif /* _HUGEMEM_H */
diff -u -r -P old/include/linux/hugeramd.h new/include/linux/hugeramd.h
--- old/include/linux/hugeramd.h Thu Jan 1 01:00:00 1970
+++ new/include/linux/hugeramd.h Mon Feb 1 10:38:45 1999
@@ -0,0 +1,26 @@
+#ifndef _HUGERAMD_H
+#define _HUGERAMD_H
+
+/*
+ * Hugeramd: special ramdisk that uses memory from the hugeram memory pool.
+ *
+ */
+
+#include <linux/ioctl.h>
+
+#ifndef __i386__
+#error Hugeramd is only available on the i386 platform.
+#endif
+
+#define HUGERAMD_MAJOR 126 /* FIXME: normal MAJOR required. */
+
+#define MAX_HUGERAMD 8 /* maximum number of ramdisks. */
+
+/* parameter: new page count*/
+#define HRDSETSIZE _IO(HUGERAMD_MAJOR,101)
+
+/* parameter: new block size */
+#define HRDSETBPS _IO(HUGERAMD_MAJOR,102)
+
+
+#endif /* _HUGERAMD_H */

--------------1D464FE45E61A46C49E47F84
Content-Type: text/plain; charset=us-ascii; name="hrsetup.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="hrsetup.c"

/*
* hrsetup.c - setup and control hugeramd devices
*/

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>

#include <linux/hugeramd.h>
#define BLKGETSIZE 0x1260 /* from <linux/blk.h> */

static char *progname;

static void show_hr(const char *device)
{
int fd;
long size;

if ((fd = open(device, O_RDWR)) < 0) {
perror(device);
return;
}
if (ioctl(fd, BLKGETSIZE, &size) < 0) {
perror("Cannot get device info.\n");
close(fd);
return;
}
printf("%s: %ld kB allocated for the ramdisk.\n",
device, size/2);
close(fd);
}

static void setsize_hr(const char *device, int newsize)
{
int fd = open (device, O_RDWR);
int res;

if(fd < 0) {
perror(device);
exit(1);
}
newsize = (newsize+3)/4; /* convert to pages. */
res = ioctl(fd, HRDSETSIZE, newsize);
close(fd);

if(res < 0) {
fprintf(stderr,"HRDSETSIZE failed, error code %d.\n",
-res);
exit(1);
}
}

static void setbps_hr(const char *device, int newbps)
{
int fd = open (device, O_RDWR);
int res;

if(fd < 0) {
perror(device);
exit(1);
}
res = ioctl(fd, HRDSETBPS, newbps);
close(fd);

if(res < 0) {
fprintf(stderr,"HRDSETSIZE failed, error code %d.\n",
-res);
exit(1);
}
}

static void del_hr(const char *device)
{
setsize_hr(device,0);
}

static int usage(void)
{
fprintf(stderr, "usage:\n\
%s hugeram_device # give info\n\
%s -d hugeram_device # delete\n\
%s -s size (kB, != 0) hugeram_device # volume size\n\
%s -b bps hugeram_device # block size\n",
progname, progname, progname, progname);
exit(1);
}

int main(int argc, char **argv)
{
int c;
int delete = 0;
int size = -1;
int bps = -1;
char* device = argv[argc-1];

progname = argv[0];
while((c=getopt(argc,argv,"ds:b:"))!=EOF) {
switch(c)
{
case 'd':
delete = 1;
break;
case 's':
size = atoi(optarg);
break;
case 'b':
bps = atoi(optarg);
break;
}
}
if(argc < 2)
usage();
if(delete)
{
del_hr(device);
show_hr(device);
return 0;
}
if(size != -1)
setsize_hr(device, size);

if(bps != -1)
setbps_hr(device, bps);

show_hr(device);
return 0;
}

--------------1D464FE45E61A46C49E47F84--

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/