blob: 19ca8d9149997b77be8fc284a15391e9a2207500 [file] [log] [blame] [edit]
/* Copyright (c) 2010 The Regents of the University of California
* Barret Rhoden <brho@cs.berkeley.edu>
* See LICENSE for details.
*
* Block device interfaces and structures */
#pragma once
#include <ros/common.h>
#include <kref.h>
#include <slab.h>
#include <pagemap.h>
#include <kthread.h>
/* All block IO is done assuming a certain size sector, which is the smallest
* possible unit of transfer between the kernel and the block layer. This can
* be bigger than what the underlying hardware can handle, but it shouldn't be
* smaller than any higher-level block (like an FS block, which are often 1 KB).
*/
#define SECTOR_SZ_LOG 9
#define SECTOR_SZ (1 << SECTOR_SZ_LOG)
/* Every block device is represented by one of these, with custom methods, as
* applicable for the type of device. Subject to massive changes. */
#define BDEV_INLINE_NAME 10
struct block_device {
int b_id;
unsigned int b_sector_sz; /* HW sector size */
unsigned long b_nr_sector; /* Total sectors on dev */
struct kref b_kref;
struct page_map b_pm;
void *b_data; /* dev-specific use */
char b_name[BDEV_INLINE_NAME];
// TODO: list or something of buffer heads (?)
// list of outstanding requests
// io scheduler
// callbacks for completion
};
/* So far, only NEEDS_ZEROED is used */
#define BH_LOCKED 0x001 /* involved in an IO op */
#define BH_UPTODATE 0x002 /* buffer is filled with file data */
#define BH_DIRTY 0x004 /* buffer is dirty */
#define BH_NEEDS_ZEROED 0x008 /* buffer should be 0'd, not read in */
/* This maps to and from a buffer within a page to a block(s) on a bdev. Some
* of it might not be needed later, etc (page, numblock). */
struct buffer_head {
struct page *bh_page; /* redundant with buffer */
void *bh_buffer;
unsigned int bh_flags;
struct buffer_head *bh_next; /* circular LL of BHs */
struct block_device *bh_bdev;
unsigned long bh_sector;
unsigned int bh_nr_sector; /* length (in sectors) */
};
struct kmem_cache *bh_kcache;
/* Buffer Head Requests. For now, just use these for dealing with non-file IO
* on a block device. Tell it what size you think blocks are. */
struct buffer_head *bdev_get_buffer(struct block_device *bdev,
unsigned long blk_num, unsigned int blk_sz);
void bdev_dirty_buffer(struct buffer_head *bh);
void bdev_put_buffer(struct buffer_head *bh);
/* This encapsulates the work of a request (instead of having a variety of
* slightly-different functions for things like read/write and scatter-gather
* ops). Reads and writes are essentially the same, so all we need is a flag to
* differentiate. This struct also serves as a tool to track the progress of a
* block request throughout its servicing. This is analagous to Linux's struct
* bio.
*
* bhs normally points to the inline version (enough for a page). kmalloc
* another array of BH pointers if you want more. The BHs do not need to be
* linked or otherwise associated with a page mapping. */
#define NR_INLINE_BH (PGSIZE >> SECTOR_SZ_LOG)
struct block_request;
struct block_request {
unsigned int flags;
void (*callback)(struct block_request *breq);
void *data;
struct semaphore sem;
struct buffer_head **bhs; /* BHs describing the IOs */
unsigned int nr_bhs;
struct buffer_head *local_bhs[NR_INLINE_BH];
};
struct kmem_cache *breq_kcache; /* for the block requests */
/* Block request flags */
#define BREQ_READ 0x001
#define BREQ_WRITE 0x002
void block_init(void);
struct block_device *get_bdev(char *path);
void free_bhs(struct page *page);
int bdev_submit_request(struct block_device *bdev, struct block_request *breq);
void generic_breq_done(struct block_request *breq);
void sleep_on_breq(struct block_request *breq);