Added virtualdrive driver. Original code by Marcus.
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2213 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,16 @@
|
|||||||
|
SubDir OBOS_TOP src tests kits storage virtualdrive ;
|
||||||
|
|
||||||
|
R5KernelAddon virtualdrive : kernel drivers bin : virtualdrive.c ;
|
||||||
|
|
||||||
|
{
|
||||||
|
local bintarget = <installed-bin>virtualdrive ;
|
||||||
|
local devtarget = <installed-dev>virtualdrive ;
|
||||||
|
LOCATE on $(bintarget) = /boot/home/config/add-ons/kernel/drivers/bin ;
|
||||||
|
LOCATE on $(devtarget)
|
||||||
|
= /boot/home/config/add-ons/kernel/drivers/dev/disk/virtual ;
|
||||||
|
File $(bintarget) : virtualdrive ;
|
||||||
|
RelSymLink $(devtarget) : $(bintarget) ;
|
||||||
|
NotFile install_virtualdrive ;
|
||||||
|
Depends install_virtualdrive : $(devtarget) ;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
|
||||||
|
This file may be used under the terms of the Be Sample Code License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LOCK_H
|
||||||
|
#define _LOCK_H
|
||||||
|
|
||||||
|
#include <BeBuild.h>
|
||||||
|
|
||||||
|
#include <OS.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#else
|
||||||
|
typedef struct lock lock;
|
||||||
|
typedef struct mlock mlock;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
struct lock {
|
||||||
|
sem_id s;
|
||||||
|
long c;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mlock {
|
||||||
|
sem_id s;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern _IMPEXP_KERNEL int new_lock(lock *l, const char *name);
|
||||||
|
extern _IMPEXP_KERNEL int free_lock(lock *l);
|
||||||
|
|
||||||
|
#define LOCK(l) if (atomic_add(&l.c, -1) <= 0) acquire_sem(l.s);
|
||||||
|
#define UNLOCK(l) if (atomic_add(&l.c, 1) < 0) release_sem(l.s);
|
||||||
|
|
||||||
|
extern _IMPEXP_KERNEL int new_mlock(mlock *l, long c, const char *name);
|
||||||
|
extern _IMPEXP_KERNEL int free_mlock(mlock *l);
|
||||||
|
|
||||||
|
#define LOCKM(l,cnt) acquire_sem_etc(l.s, cnt, 0, 0)
|
||||||
|
#define UNLOCKM(l,cnt) release_sem_etc(l.s, cnt, 0)
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,444 @@
|
|||||||
|
// ----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// File Name: virtualdrive.c
|
||||||
|
//
|
||||||
|
// Description: Driver that emulates virtual drives.
|
||||||
|
//
|
||||||
|
// Author: Marcus Overhagen <[email protected]>
|
||||||
|
// Ingo Weinhold <[email protected]>
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include <KernelExport.h>
|
||||||
|
#include <Drivers.h>
|
||||||
|
#include <Errors.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include "lock.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
[2:07] <geist> when you open the file in the driver, use stat() to see if it's a file. if it is, call ioctl 10000 on the underlying file
|
||||||
|
[2:07] <geist> that's the disable-cache ioctl
|
||||||
|
[2:08] <geist> bfs is probably doing the same algorithm, and seeing that you are a device and not a file, and so it doesn't call 10000 on you
|
||||||
|
[2:08] <marcus_o> thanks, I will try calling it
|
||||||
|
[2:08] <geist> and dont bother using dosfs as a host fs, it wont work
|
||||||
|
[2:09] <geist> bfs is the only fs that's reasonably safe being reentered like that, but only if the underlying one is opened with the cache disabled on that file
|
||||||
|
[2:09] <geist> that ioctl is used on the swap file as well
|
||||||
|
[2:10] <marcus_o> I'm currently allocating memory in the driver's write() function hook
|
||||||
|
[2:10] <geist> cant do that
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define TRACE dprintf
|
||||||
|
//#define TRACE (void)
|
||||||
|
#define MB (1024LL * 1024LL)
|
||||||
|
|
||||||
|
static int dev_num_for_path(const char *path);
|
||||||
|
|
||||||
|
int32 api_version = B_CUR_DRIVER_API_VERSION;
|
||||||
|
|
||||||
|
lock driverlock;
|
||||||
|
|
||||||
|
typedef struct device_inf {
|
||||||
|
int32 opencount;
|
||||||
|
uint8 *buffer;
|
||||||
|
int fd;
|
||||||
|
int64 size;
|
||||||
|
bool hidden;
|
||||||
|
char file[1024];
|
||||||
|
const char device_path[1024];
|
||||||
|
} device_inf;
|
||||||
|
|
||||||
|
struct device_inf device_info[] =
|
||||||
|
{
|
||||||
|
{ 0, 0, 0, 64 * MB, false, "/tmp/virtualdrive64", "disk/virtual/0/raw" },
|
||||||
|
{ 0, 0, 0, 32 * MB, false, "/tmp/virtualdrive32", "disk/virtual/1/raw" },
|
||||||
|
};
|
||||||
|
|
||||||
|
const int kDeviceCount = sizeof(device_info) / sizeof(device_inf);
|
||||||
|
|
||||||
|
/* ----------
|
||||||
|
init_hardware - called once the first time the driver is loaded
|
||||||
|
----- */
|
||||||
|
status_t
|
||||||
|
init_hardware (void)
|
||||||
|
{
|
||||||
|
TRACE("virtualdrive: init_hardware\n");
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------
|
||||||
|
init_driver - optional function - called every time the driver
|
||||||
|
is loaded.
|
||||||
|
----- */
|
||||||
|
status_t
|
||||||
|
init_driver (void)
|
||||||
|
{
|
||||||
|
TRACE("virtualdrive: init\n");
|
||||||
|
|
||||||
|
new_lock(&driverlock, "virtualdrive lock");
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------
|
||||||
|
uninit_driver - optional function - called every time the driver
|
||||||
|
is unloaded
|
||||||
|
----- */
|
||||||
|
void
|
||||||
|
uninit_driver (void)
|
||||||
|
{
|
||||||
|
TRACE("virtualdrive: uninit\n");
|
||||||
|
free_lock(&driverlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------
|
||||||
|
virtualdrive_open - handle open() calls
|
||||||
|
----- */
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
virtualdrive_open (const char *name, uint32 flags, void** cookie)
|
||||||
|
{
|
||||||
|
int dev_num;
|
||||||
|
TRACE("virtualdrive: open %s\n",name);
|
||||||
|
|
||||||
|
*cookie = (void *) -1;
|
||||||
|
|
||||||
|
if (0 == strcmp(name,"disk/virtual/virtualdrive")) {
|
||||||
|
TRACE("virtualdrive: rejected!\n");
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOCK(driverlock);
|
||||||
|
|
||||||
|
dev_num = dev_num_for_path(name);
|
||||||
|
|
||||||
|
TRACE("virtualdrive: dev_num %d!\n",dev_num);
|
||||||
|
|
||||||
|
if (dev_num < 0 || dev_num >= kDeviceCount) {
|
||||||
|
TRACE("virtualdrive: wrong index!\n");
|
||||||
|
UNLOCK(driverlock);
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (device_info[dev_num].hidden) {
|
||||||
|
TRACE("virtualdrive: device is hidden!\n");
|
||||||
|
UNLOCK(driverlock);
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// store index in cookie
|
||||||
|
*cookie = (void *) dev_num;
|
||||||
|
|
||||||
|
device_info[dev_num].opencount++;
|
||||||
|
|
||||||
|
if (device_info[dev_num].opencount == 1) {
|
||||||
|
char c;
|
||||||
|
const char *file;
|
||||||
|
file = device_info[dev_num].file;
|
||||||
|
TRACE("virtualdrive: opening %s\n",file);
|
||||||
|
device_info[dev_num].fd = open(file,O_RDWR | O_CREAT,0666);
|
||||||
|
if (device_info[dev_num].fd < 0) {
|
||||||
|
device_info[dev_num].opencount--;
|
||||||
|
TRACE("virtualdrive: file open failed!\n");
|
||||||
|
// remove index from cookie
|
||||||
|
*cookie = (void *) -1;
|
||||||
|
UNLOCK(driverlock);
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// disable caching for underlying file! (else this driver will deadlock)
|
||||||
|
if (0 != ioctl(device_info[dev_num].fd,10000)) {
|
||||||
|
TRACE("virtualdrive: disable caching ioctl failed\n");
|
||||||
|
}
|
||||||
|
// set file size
|
||||||
|
lseek(device_info[dev_num].fd,device_info[dev_num].size - 1,0);
|
||||||
|
read(device_info[dev_num].fd,&c,1);
|
||||||
|
lseek(device_info[dev_num].fd,device_info[dev_num].size - 1,0);
|
||||||
|
write(device_info[dev_num].fd,&c,1);
|
||||||
|
|
||||||
|
// device_info[dev_num].buffer = (uint8*) malloc(65536);
|
||||||
|
TRACE("virtualdrive: file opened\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
UNLOCK(driverlock);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------
|
||||||
|
virtualdrive_close - handle close() calls
|
||||||
|
----- */
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
virtualdrive_close (void* cookie)
|
||||||
|
{
|
||||||
|
int dev_num;
|
||||||
|
TRACE("virtualdrive: close\n");
|
||||||
|
|
||||||
|
dev_num = (int)cookie;
|
||||||
|
|
||||||
|
TRACE("virtualdrive: dev_num = %d\n",dev_num);
|
||||||
|
if (dev_num < 0 || dev_num >= kDeviceCount)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
LOCK(driverlock);
|
||||||
|
|
||||||
|
device_info[dev_num].opencount--;
|
||||||
|
|
||||||
|
if (device_info[dev_num].opencount == 0) {
|
||||||
|
close(device_info[dev_num].fd);
|
||||||
|
// free(device_info[dev_num].buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
UNLOCK(driverlock);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------
|
||||||
|
virtualdrive_read - handle read() calls
|
||||||
|
----- */
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
virtualdrive_read (void* cookie, off_t position, void *buffer, size_t* num_bytes)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
TRACE("virtualdrive: read pos = 0x%08Lx, bytes = 0x%08lx\n",position,*num_bytes);
|
||||||
|
fd = device_info[(int) cookie].fd;
|
||||||
|
if (fd < 0)
|
||||||
|
return B_ERROR;
|
||||||
|
if (position & 511)
|
||||||
|
return B_ERROR;
|
||||||
|
if (*num_bytes & 511)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
LOCK(driverlock);
|
||||||
|
lseek(fd,position,0);
|
||||||
|
read(fd,buffer,*num_bytes);
|
||||||
|
UNLOCK(driverlock);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------
|
||||||
|
virtualdrive_write - handle write() calls
|
||||||
|
----- */
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
virtualdrive_write (void* cookie, off_t position, const void* buffer, size_t* num_bytes)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
TRACE("virtualdrive: write pos = 0x%08Lx, bytes = 0x%08lx\n",position,*num_bytes);
|
||||||
|
fd = device_info[(int) cookie].fd;
|
||||||
|
if (fd < 0)
|
||||||
|
return B_ERROR;
|
||||||
|
if (position & 511)
|
||||||
|
return B_ERROR;
|
||||||
|
if (*num_bytes & 511)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
LOCK(driverlock);
|
||||||
|
lseek(fd,position,0);
|
||||||
|
write(fd,buffer,*num_bytes);
|
||||||
|
UNLOCK(driverlock);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------
|
||||||
|
virtualdrive_control - handle ioctl calls
|
||||||
|
----- */
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
virtualdrive_control (void* cookie, uint32 op, void* arg, size_t len)
|
||||||
|
{
|
||||||
|
device_geometry *dg;
|
||||||
|
partition_info *pi;
|
||||||
|
struct device_inf *dev;
|
||||||
|
|
||||||
|
TRACE("virtualdrive: ioctl\n");
|
||||||
|
|
||||||
|
dev = &device_info[(int)cookie];
|
||||||
|
|
||||||
|
switch (op) {
|
||||||
|
case B_GET_DEVICE_SIZE:
|
||||||
|
TRACE("virtualdrive: free\n");
|
||||||
|
*(size_t*)arg = dev->size;
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
case B_SET_NONBLOCKING_IO:
|
||||||
|
TRACE("virtualdrive: B_SET_NONBLOCKING_IO\n");
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
case B_SET_BLOCKING_IO:
|
||||||
|
TRACE("virtualdrive: B_SET_BLOCKING_IO\n");
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
case B_GET_READ_STATUS:
|
||||||
|
TRACE("virtualdrive: B_GET_READ_STATUS\n");
|
||||||
|
*(bool*)arg = true;
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
case B_GET_WRITE_STATUS:
|
||||||
|
TRACE("virtualdrive: B_GET_WRITE_STATUS\n");
|
||||||
|
*(bool*)arg = true;
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
case B_GET_ICON:
|
||||||
|
TRACE("virtualdrive: B_GET_ICON\n");
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
case B_GET_GEOMETRY:
|
||||||
|
TRACE("virtualdrive: B_GET_GEOMETRY\n");
|
||||||
|
dg = (device_geometry *)arg;
|
||||||
|
dg->bytes_per_sector = 512;
|
||||||
|
dg->sectors_per_track = dev->size / 512;
|
||||||
|
dg->cylinder_count = 1;
|
||||||
|
dg->head_count = 1;
|
||||||
|
dg->device_type = B_DISK;
|
||||||
|
dg->removable = false;
|
||||||
|
dg->read_only = false;
|
||||||
|
dg->write_once = false;
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
case B_GET_BIOS_GEOMETRY:
|
||||||
|
TRACE("virtualdrive: B_GET_BIOS_GEOMETRY\n");
|
||||||
|
dg = (device_geometry *)arg;
|
||||||
|
dg->bytes_per_sector = 512;
|
||||||
|
dg->sectors_per_track = dev->size / (512 * 1024);
|
||||||
|
dg->cylinder_count = 1024;
|
||||||
|
dg->head_count = 1;
|
||||||
|
dg->device_type = B_DISK;
|
||||||
|
dg->removable = false;
|
||||||
|
dg->read_only = false;
|
||||||
|
dg->write_once = false;
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
case B_GET_PARTITION_INFO:
|
||||||
|
// this one never gets called
|
||||||
|
TRACE("virtualdrive: B_GET_PARTITION_INFO\n");
|
||||||
|
pi = (partition_info *)arg;
|
||||||
|
pi->offset = 0;
|
||||||
|
pi->size = dev->size;
|
||||||
|
pi->logical_block_size = 512;
|
||||||
|
pi->session = 1;
|
||||||
|
pi->partition = 1;
|
||||||
|
strcpy(pi->device,"/boot/home/dummy");
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
case B_GET_MEDIA_STATUS:
|
||||||
|
TRACE("virtualdrive: B_GET_MEDIA_STATUS\n");
|
||||||
|
*(status_t*)arg = B_NO_ERROR;
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
case B_SET_UNINTERRUPTABLE_IO:
|
||||||
|
TRACE("virtualdrive: B_SET_UNINTERRUPTABLE_IO\n");
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
case B_SET_INTERRUPTABLE_IO:
|
||||||
|
TRACE("virtualdrive: B_SET_INTERRUPTABLE_IO\n");
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
case B_FLUSH_DRIVE_CACHE:
|
||||||
|
TRACE("virtualdrive: B_FLUSH_DRIVE_CACHE\n");
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
case B_GET_BIOS_DRIVE_ID:
|
||||||
|
TRACE("virtualdrive: B_GET_BIOS_DRIVE_ID\n");
|
||||||
|
*(uint8*)arg = 0xF8;
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
case B_GET_DRIVER_FOR_DEVICE:
|
||||||
|
case B_SET_DEVICE_SIZE:
|
||||||
|
case B_SET_PARTITION:
|
||||||
|
case B_FORMAT_DEVICE:
|
||||||
|
case B_EJECT_DEVICE:
|
||||||
|
case B_LOAD_MEDIA:
|
||||||
|
case B_GET_NEXT_OPEN_DEVICE:
|
||||||
|
TRACE("virtualdrive: another ioctl: %lx (%lu)\n", op, op);
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
default:
|
||||||
|
TRACE("virtualdrive: unknown ioctl: %lx (%lu)\n", op, op);
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -----
|
||||||
|
virtualdrive_free - called after the last device is closed, and after
|
||||||
|
all i/o is complete.
|
||||||
|
----- */
|
||||||
|
static status_t
|
||||||
|
virtualdrive_free (void* cookie)
|
||||||
|
{
|
||||||
|
TRACE("virtualdrive: free\n");
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -----
|
||||||
|
null-terminated array of device names supported by this driver
|
||||||
|
----- */
|
||||||
|
|
||||||
|
static const char *virtualdrive_name[] = {
|
||||||
|
// "disk/virtual/virtualdrive",
|
||||||
|
"disk/virtual/0/raw",
|
||||||
|
"disk/virtual/1/raw",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
/* -----
|
||||||
|
function pointers for the device hooks entry points
|
||||||
|
----- */
|
||||||
|
|
||||||
|
device_hooks virtualdrive_hooks = {
|
||||||
|
virtualdrive_open, /* -> open entry point */
|
||||||
|
virtualdrive_close, /* -> close entry point */
|
||||||
|
virtualdrive_free, /* -> free cookie */
|
||||||
|
virtualdrive_control, /* -> control entry point */
|
||||||
|
virtualdrive_read, /* -> read entry point */
|
||||||
|
virtualdrive_write /* -> write entry point */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ----------
|
||||||
|
publish_devices - return a null-terminated array of devices
|
||||||
|
supported by this driver.
|
||||||
|
----- */
|
||||||
|
|
||||||
|
const char**
|
||||||
|
publish_devices()
|
||||||
|
{
|
||||||
|
TRACE("virtualdrive: publish_devices\n");
|
||||||
|
return virtualdrive_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------
|
||||||
|
find_device - return ptr to device hooks structure for a
|
||||||
|
given device name
|
||||||
|
----- */
|
||||||
|
|
||||||
|
device_hooks*
|
||||||
|
find_device(const char* name)
|
||||||
|
{
|
||||||
|
return &virtualdrive_hooks;
|
||||||
|
}
|
||||||
|
|
||||||
|
// dev_num_for_path
|
||||||
|
static
|
||||||
|
int
|
||||||
|
dev_num_for_path(const char *path)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < kDeviceCount; i++) {
|
||||||
|
if (!strcmp(path, device_info[i].device_path))
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user