minios: add posix io for blkfront

This patch adds posix io support (read,write,lseek) to block devices
using blkfront.

Signed-off-by: Matthew Fioravante <matthew.fioravante@jhuapl.edu>
Acked-by: Samuel Thibault <samuel.thibault@ens-lyons.org>
Committed-by: Ian Campbell <ian.campbell@citrix.com>
This commit is contained in:
Matthew Fioravante committed 2012-10-09 10:39:08 +01:00
1 parent 8e19000995
commit 78ef2bb502
4 files changed
+224 -2

No files matched your search

+169
View File
@@ -392,6 +392,7 @@ void blkfront_aio(struct blkfront_aiocb *aiocbp, int write)
static void blkfront_aio_cb(struct blkfront_aiocb *aiocbp, int ret)
{
aiocbp->data = (void*) 1;
aiocbp->aio_cb = NULL;
}
void blkfront_io(struct blkfront_aiocb *aiocbp, int write)
@@ -547,9 +548,177 @@ moretodo:
#ifdef HAVE_LIBC
int blkfront_open(struct blkfront_dev *dev)
{
/* Silently prevent multiple opens */
if(dev->fd != -1) {
return dev->fd;
}
dev->fd = alloc_fd(FTYPE_BLK);
printk("blk_open(%s) -> %d\n", dev->nodename, dev->fd);
files[dev->fd].blk.dev = dev;
files[dev->fd].blk.offset = 0;
return dev->fd;
}
int blkfront_posix_rwop(int fd, uint8_t* buf, size_t count, int write)
{
struct blkfront_dev* dev = files[fd].blk.dev;
off_t offset = files[fd].blk.offset;
struct blkfront_aiocb aiocb;
unsigned long long disksize = dev->info.sectors * dev->info.sector_size;
unsigned int blocksize = dev->info.sector_size;
int blknum;
int blkoff;
size_t bytes;
int rc = 0;
int alignedbuf = 0;
uint8_t* copybuf = NULL;
/* RW 0 bytes is just a NOP */
if(count == 0) {
return 0;
}
/* Check for NULL buffer */
if( buf == NULL ) {
errno = EFAULT;
return -1;
}
/* Write mode checks */
if(write) {
/*Make sure we have write permission */
if(dev->info.info & VDISK_READONLY
|| (dev->info.mode != O_RDWR && dev->info.mode != O_WRONLY)) {
errno = EACCES;
return -1;
}
/*Make sure disk is big enough for this write */
if(offset + count > disksize) {
errno = ENOSPC;
return -1;
}
}
/* Read mode checks */
else
{
/* Reading past the disk? Just return 0 */
if(offset >= disksize) {
return 0;
}
/*If the requested read is bigger than the disk, just
* read as much as we can until the end */
if(offset + count > disksize) {
count = disksize - offset;
}
}
/* Determine which block to start at and at which offset inside of it */
blknum = offset / blocksize;
blkoff = offset % blocksize;
/* Optimization: We need to check if buf is aligned to the sector size.
* This is somewhat tricky code. We have to add the blocksize - block offset
* because the first block may be a partial block and then for every subsequent
* block rw the buffer will be offset.*/
if(!((uintptr_t) (buf +(blocksize - blkoff)) & (dev->info.sector_size-1))) {
alignedbuf = 1;
}
/* Setup aiocb block object */
aiocb.aio_dev = dev;
aiocb.aio_offset = blknum * blocksize;
aiocb.aio_cb = NULL;
aiocb.data = NULL;
/* If our buffer is unaligned or its aligned but we will need to rw a partial block
* then a copy will have to be done */
if(!alignedbuf || blkoff != 0 || count % blocksize != 0) {
copybuf = _xmalloc(blocksize, dev->info.sector_size);
}
rc = count;
while(count > 0) {
/* determine how many bytes to read/write from/to the current block buffer */
if(!alignedbuf || blkoff != 0 || count < blocksize) {
/* This is the case for unaligned R/W or partial block */
bytes = count < blocksize - blkoff ? count : blocksize - blkoff;
aiocb.aio_nbytes = blocksize;
} else {
/* We can optimize further if buffer is page aligned */
int not_page_aligned = 0;
if(((uintptr_t)buf) & (PAGE_SIZE -1)) {
not_page_aligned = 1;
}
/* For an aligned R/W we can read up to the maximum transfer size */
bytes = count > (BLKIF_MAX_SEGMENTS_PER_REQUEST-not_page_aligned)*PAGE_SIZE
? (BLKIF_MAX_SEGMENTS_PER_REQUEST-not_page_aligned)*PAGE_SIZE
: count & ~(blocksize -1);
aiocb.aio_nbytes = bytes;
}
/* read operation */
if(!write) {
if (alignedbuf && bytes >= blocksize) {
/* If aligned and were reading a whole block, just read right into buf */
aiocb.aio_buf = buf;
blkfront_read(&aiocb);
} else {
/* If not then we have to do a copy */
aiocb.aio_buf = copybuf;
blkfront_read(&aiocb);
memcpy(buf, &copybuf[blkoff], bytes);
}
}
/* Write operation */
else {
if(alignedbuf && bytes >= blocksize) {
/* If aligned and were writing a whole block, just write directly from buf */
aiocb.aio_buf = buf;
blkfront_write(&aiocb);
} else {
/* If not then we have to do a copy. */
aiocb.aio_buf = copybuf;
/* If we're writing a partial block, we need to read the current contents first
* so we don't overwrite the extra bits with garbage */
if(blkoff != 0 || bytes < blocksize) {
blkfront_read(&aiocb);
}
memcpy(&copybuf[blkoff], buf, bytes);
blkfront_write(&aiocb);
}
}
/* Will start at beginning of all remaining blocks */
blkoff = 0;
/* Increment counters and continue */
count -= bytes;
buf += bytes;
if(bytes < blocksize) {
//At minimum we read one block
aiocb.aio_offset += blocksize;
} else {
//If we read more than a block, was a multiple of blocksize
aiocb.aio_offset += bytes;
}
}
free(copybuf);
files[fd].blk.offset += rc;
return rc;
}
int blkfront_posix_fstat(int fd, struct stat* buf)
{
struct blkfront_dev* dev = files[fd].blk.dev;
buf->st_mode = dev->info.mode;
buf->st_uid = 0;
buf->st_gid = 0;
buf->st_size = dev->info.sectors * dev->info.sector_size;
buf->st_atime = buf->st_mtime = buf->st_ctime = time(NULL);
return 0;
}
#endif
+10
View File
@@ -28,7 +28,17 @@ struct blkfront_info
};
struct blkfront_dev *init_blkfront(char *nodename, struct blkfront_info *info);
#ifdef HAVE_LIBC
#include <sys/stat.h>
/* POSIX IO functions:
* use blkfront_open() to get a file descriptor to the block device
* Don't use the other blkfront posix functions here directly, instead use
* read(), write(), lseek() and fstat() on the file descriptor
*/
int blkfront_open(struct blkfront_dev *dev);
int blkfront_posix_rwop(int fd, uint8_t* buf, size_t count, int write);
#define blkfront_posix_write(fd, buf, count) blkfront_posix_rwop(fd, (uint8_t*)buf, count, 1)
#define blkfront_posix_read(fd, buf, count) blkfront_posix_rwop(fd, (uint8_t*)buf, count, 0)
int blkfront_posix_fstat(int fd, struct stat* buf);
#endif
void blkfront_aio(struct blkfront_aiocb *aiocbp, int write);
#define blkfront_aio_read(aiocbp) blkfront_aio(aiocbp, 0)
+1
View File
@@ -174,6 +174,7 @@ extern struct file {
} tap;
struct {
struct blkfront_dev *dev;
off_t offset;
} blk;
struct {
struct kbdfront_dev *dev;
+44 -2
View File
@@ -288,6 +288,11 @@ int read(int fd, void *buf, size_t nbytes)
}
return ret * sizeof(union xenfb_in_event);
}
#endif
#ifdef CONFIG_BLKFRONT
case FTYPE_BLK: {
return blkfront_posix_read(fd, buf, nbytes);
}
#endif
default:
break;
@@ -320,6 +325,10 @@ int write(int fd, const void *buf, size_t nbytes)
case FTYPE_TAP:
netfront_xmit(files[fd].tap.dev, (void*) buf, nbytes);
return nbytes;
#endif
#ifdef CONFIG_BLKFRONT
case FTYPE_BLK:
return blkfront_posix_write(fd, buf, nbytes);
#endif
default:
break;
@@ -331,8 +340,37 @@ int write(int fd, const void *buf, size_t nbytes)
off_t lseek(int fd, off_t offset, int whence)
{
errno = ESPIPE;
return (off_t) -1;
switch(files[fd].type) {
#ifdef CONFIG_BLKFRONT
case FTYPE_BLK:
switch (whence) {
case SEEK_SET:
files[fd].file.offset = offset;
break;
case SEEK_CUR:
files[fd].file.offset += offset;
break;
case SEEK_END:
{
struct stat st;
int ret;
ret = fstat(fd, &st);
if (ret)
return -1;
files[fd].file.offset = st.st_size + offset;
break;
}
default:
errno = EINVAL;
return -1;
}
return files[fd].file.offset;
break;
#endif
default: /* Not implemented on this FTYPE */
errno = ESPIPE;
return (off_t) -1;
}
}
int fsync(int fd) {
@@ -447,6 +485,10 @@ int fstat(int fd, struct stat *buf)
buf->st_ctime = time(NULL);
return 0;
}
#ifdef CONFIG_BLKFRONT
case FTYPE_BLK:
return blkfront_posix_fstat(fd, buf);
#endif
default:
break;
}
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.