patch-2.3.43 linux/drivers/block/ll_rw_blk.c
Next file: linux/drivers/block/loop.c
Previous file: linux/drivers/block/linear.h
Back to the patch index
Back to the overall index
- Lines: 612
- Date:
Wed Feb 9 19:34:53 2000
- Orig file:
v2.3.42/linux/drivers/block/ll_rw_blk.c
- Orig date:
Fri Jan 28 15:09:07 2000
diff -u --recursive --new-file v2.3.42/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
@@ -23,6 +23,7 @@
#include <asm/io.h>
#include <linux/blk.h>
#include <linux/highmem.h>
+#include <linux/raid/md.h>
#include <linux/module.h>
@@ -65,9 +66,9 @@
*/
DECLARE_WAIT_QUEUE_HEAD(wait_for_request);
-/* This specifies how many sectors to read ahead on the disk. */
+/* This specifies how many sectors to read ahead on the disk. */
-int read_ahead[MAX_BLKDEV] = {0, };
+int read_ahead[MAX_BLKDEV];
/* blk_dev_struct is:
* *request_fn
@@ -83,7 +84,7 @@
*
* if (!blk_size[MAJOR]) then no minor size checking is done.
*/
-int * blk_size[MAX_BLKDEV] = { NULL, NULL, };
+int * blk_size[MAX_BLKDEV];
/*
* blksize_size contains the size of all block-devices:
@@ -92,7 +93,7 @@
*
* if (!blksize_size[MAJOR]) then 1024 bytes is assumed.
*/
-int * blksize_size[MAX_BLKDEV] = { NULL, NULL, };
+int * blksize_size[MAX_BLKDEV];
/*
* hardsect_size contains the size of the hardware sector of a device.
@@ -106,17 +107,17 @@
* This is currently set by some scsi devices and read by the msdos fs driver.
* Other uses may appear later.
*/
-int * hardsect_size[MAX_BLKDEV] = { NULL, NULL, };
+int * hardsect_size[MAX_BLKDEV];
/*
* The following tunes the read-ahead algorithm in mm/filemap.c
*/
-int * max_readahead[MAX_BLKDEV] = { NULL, NULL, };
+int * max_readahead[MAX_BLKDEV];
/*
* Max number of sectors per request
*/
-int * max_sectors[MAX_BLKDEV] = { NULL, NULL, };
+int * max_sectors[MAX_BLKDEV];
static inline int get_max_sectors(kdev_t dev)
{
@@ -126,18 +127,24 @@
}
/*
- * Is called with the request spinlock aquired.
* NOTE: the device-specific queue() functions
* have to be atomic!
*/
-static inline request_queue_t *get_queue(kdev_t dev)
+request_queue_t * blk_get_queue (kdev_t dev)
{
int major = MAJOR(dev);
struct blk_dev_struct *bdev = blk_dev + major;
+ unsigned long flags;
+ request_queue_t *ret;
+ spin_lock_irqsave(&io_request_lock,flags);
if (bdev->queue)
- return bdev->queue(dev);
- return &blk_dev[major].request_queue;
+ ret = bdev->queue(dev);
+ else
+ ret = &blk_dev[major].request_queue;
+ spin_unlock_irqrestore(&io_request_lock,flags);
+
+ return ret;
}
void blk_cleanup_queue(request_queue_t * q)
@@ -147,12 +154,17 @@
void blk_queue_headactive(request_queue_t * q, int active)
{
- q->head_active = active;
+ q->head_active = active;
+}
+
+void blk_queue_pluggable (request_queue_t * q, plug_device_fn *plug)
+{
+ q->plug_device_fn = plug;
}
-void blk_queue_pluggable(request_queue_t * q, int use_plug)
+void blk_queue_make_request(request_queue_t * q, make_request_fn * mfn)
{
- q->use_plug = use_plug;
+ q->make_request_fn = mfn;
}
static int ll_merge_fn(request_queue_t *q, struct request *req,
@@ -185,42 +197,23 @@
void blk_init_queue(request_queue_t * q, request_fn_proc * rfn)
{
- q->request_fn = rfn;
+ q->request_fn = rfn;
q->current_request = NULL;
- q->merge_fn = ll_merge_fn;
+ q->merge_fn = ll_merge_fn;
q->merge_requests_fn = ll_merge_requests_fn;
- q->plug_tq.sync = 0;
- q->plug_tq.routine = unplug_device;
- q->plug_tq.data = q;
- q->plugged = 0;
+ q->make_request_fn = NULL;
+ q->plug_tq.sync = 0;
+ q->plug_tq.routine = &generic_unplug_device;
+ q->plug_tq.data = q;
+ q->plugged = 0;
/*
* These booleans describe the queue properties. We set the
* default (and most common) values here. Other drivers can
* use the appropriate functions to alter the queue properties.
* as appropriate.
*/
- q->use_plug = 1;
- q->head_active = 1;
-}
-
-/*
- * remove the plug and let it rip..
- */
-void unplug_device(void * data)
-{
- request_queue_t * q = (request_queue_t *) data;
- unsigned long flags;
-
- spin_lock_irqsave(&io_request_lock,flags);
- if( q->plugged )
- {
- q->plugged = 0;
- if( q->current_request != NULL )
- {
- (q->request_fn)(q);
- }
- }
- spin_unlock_irqrestore(&io_request_lock,flags);
+ q->plug_device_fn = NULL;
+ q->head_active = 1;
}
/*
@@ -231,8 +224,12 @@
* This is called with interrupts off and no requests on the queue.
* (and with the request spinlock aquired)
*/
-static inline void plug_device(request_queue_t * q)
+inline void generic_plug_device (request_queue_t *q, kdev_t dev)
{
+ if (MAJOR(dev) == MD_MAJOR) {
+ spin_unlock_irq(&io_request_lock);
+ BUG();
+ }
if (q->current_request)
return;
@@ -241,6 +238,23 @@
}
/*
+ * remove the plug and let it rip..
+ */
+void generic_unplug_device(void * data)
+{
+ request_queue_t * q = (request_queue_t *) data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock,flags);
+ if (q->plugged) {
+ q->plugged = 0;
+ if (q->current_request)
+ (q->request_fn)(q);
+ }
+ spin_unlock_irqrestore(&io_request_lock,flags);
+}
+
+/*
* look for a free request in the first N entries.
* NOTE: interrupts must be disabled on the way in (on SMP the request queue
* spinlock has to be aquired), and will still be disabled on the way out.
@@ -337,7 +351,7 @@
}
static inline void drive_stat_acct(struct request *req,
- unsigned long nr_sectors, int new_io)
+ unsigned long nr_sectors, int new_io)
{
int major = MAJOR(req->rq_dev);
int minor = MINOR(req->rq_dev);
@@ -384,23 +398,17 @@
* which is important for drive_stat_acct() above.
*/
-static void add_request(request_queue_t * q, struct request * req)
+static inline void __add_request(request_queue_t * q, struct request * req)
{
int major = MAJOR(req->rq_dev);
struct request * tmp;
- unsigned long flags;
drive_stat_acct(req, req->nr_sectors, 1);
req->next = NULL;
- /*
- * We use the goto to reduce locking complexity
- */
- spin_lock_irqsave(&io_request_lock,flags);
-
if (!(tmp = q->current_request)) {
q->current_request = req;
- goto out;
+ return;
}
for ( ; tmp->next ; tmp = tmp->next) {
const int after_current = IN_ORDER(tmp,req);
@@ -420,7 +428,7 @@
/*
* FIXME(eric) I don't understand why there is a need for this
* special case code. It clearly doesn't fit any more with
- * the new queueing architecture, and it got added in 2.3.10.
+ * the new queueing architecture, and it got added in 2.3.10.
* I am leaving this in here until I hear back from the COMPAQ
* people.
*/
@@ -433,16 +441,13 @@
{
(q->request_fn)(q);
}
-
-out:
- spin_unlock_irqrestore(&io_request_lock,flags);
}
/*
* Has to be called with the request spinlock aquired
*/
static inline void attempt_merge (request_queue_t * q,
- struct request *req,
+ struct request *req,
int max_sectors)
{
struct request *next = req->next;
@@ -453,7 +458,6 @@
return;
if (next->sem || req->cmd != next->cmd || req->rq_dev != next->rq_dev || req->nr_sectors + next->nr_sectors > max_sectors)
return;
-
/*
* If we are not allowed to merge these requests, then
* return. If we are allowed to merge, then the count
@@ -471,11 +475,10 @@
wake_up (&wait_for_request);
}
-static void __make_request(request_queue_t * q,
- int major,
- int rw,
+static inline void __make_request(request_queue_t * q, int rw,
struct buffer_head * bh)
{
+ int major = MAJOR(bh->b_rdev);
unsigned int sector, count;
struct request * req;
int rw_ahead, max_req, max_sectors;
@@ -484,28 +487,22 @@
count = bh->b_size >> 9;
sector = bh->b_rsector;
- /* It had better not be a new buffer by the time we see it */
- if (buffer_new(bh))
- BUG();
-
- /* Only one thread can actually submit the I/O. */
- if (test_and_set_bit(BH_Lock, &bh->b_state))
- return;
-
if (blk_size[major]) {
unsigned long maxsector = (blk_size[major][MINOR(bh->b_rdev)] << 1) + 1;
if (maxsector < count || maxsector - count < sector) {
bh->b_state &= (1 << BH_Lock) | (1 << BH_Mapped);
- /* This may well happen - the kernel calls bread()
- without checking the size of the device, e.g.,
- when mounting a device. */
+ if (!blk_size[major][MINOR(bh->b_rdev)])
+ goto end_io;
+ /* This may well happen - the kernel calls bread()
+ without checking the size of the device, e.g.,
+ when mounting a device. */
printk(KERN_INFO
- "attempt to access beyond end of device\n");
+ "attempt to access beyond end of device\n");
printk(KERN_INFO "%s: rw=%d, want=%d, limit=%d\n",
- kdevname(bh->b_rdev), rw,
- (sector + count)>>1,
- blk_size[major][MINOR(bh->b_rdev)]);
+ kdevname(bh->b_rdev), rw,
+ (sector + count)>>1,
+ blk_size[major][MINOR(bh->b_rdev)]);
goto end_io;
}
}
@@ -539,8 +536,7 @@
max_req = (NR_REQUEST * 2) / 3;
break;
default:
- printk(KERN_ERR "make_request: bad block dev cmd,"
- " must be R/W/RA/WA\n");
+ BUG();
goto end_io;
}
@@ -561,10 +557,12 @@
#endif
/* look for a free request. */
- /* Loop uses two requests, 1 for loop and 1 for the real device.
- * Cut max_req in half to avoid running out and deadlocking. */
+ /*
+ * Loop uses two requests, 1 for loop and 1 for the real device.
+ * Cut max_req in half to avoid running out and deadlocking.
+ */
if ((major == LOOP_MAJOR) || (major == NBD_MAJOR))
- max_req >>= 1;
+ max_req >>= 1;
/*
* Try to coalesce the new request with old requests
@@ -579,10 +577,10 @@
req = q->current_request;
if (!req) {
/* MD and loop can't handle plugging without deadlocking */
- if (major != MD_MAJOR && major != LOOP_MAJOR &&
- major != DDV_MAJOR && major != NBD_MAJOR
- && q->use_plug)
- plug_device(q); /* is atomic */
+ if (q->plug_device_fn)
+ q->plug_device_fn(q, bh->b_rdev); /* is atomic */
+ else
+ generic_plug_device(q, bh->b_rdev); /* is atomic */
goto get_rq;
}
@@ -667,13 +665,34 @@
get_rq:
req = get_request(max_req, bh->b_rdev);
- spin_unlock_irqrestore(&io_request_lock,flags);
-
-/* if no request available: if rw_ahead, forget it; otherwise try again blocking.. */
+ /*
+ * if no request available: if rw_ahead, forget it,
+ * otherwise try again blocking..
+ */
if (!req) {
+ spin_unlock_irqrestore(&io_request_lock,flags);
if (rw_ahead)
goto end_io;
req = __get_request_wait(max_req, bh->b_rdev);
+ spin_lock_irqsave(&io_request_lock,flags);
+ }
+ /*
+ * Dont start the IO if the buffer has been
+ * invalidated meanwhile. (we have to do this
+ * within the io request lock and atomically
+ * before adding the request, see buffer.c's
+ * insert_into_queues_exclusive() function.
+ */
+ if (!test_bit(BH_Req, &bh->b_state)) {
+ req->rq_status = RQ_INACTIVE;
+ spin_unlock_irqrestore(&io_request_lock,flags);
+ /*
+ * A fake 'everything went ok' completion event.
+ * The bh doesnt matter anymore, but we should not
+ * signal errors to RAID levels.
+ */
+ bh->b_end_io(bh, 1);
+ return;
}
/* fill up the request-info, and add it to the queue */
@@ -689,52 +708,51 @@
req->bh = bh;
req->bhtail = bh;
req->next = NULL;
- add_request(q, req);
+ __add_request(q, req);
+ spin_unlock_irqrestore(&io_request_lock, flags);
return;
end_io:
bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state));
}
-void make_request(int major,int rw, struct buffer_head * bh)
+void generic_make_request(int rw, struct buffer_head * bh)
{
request_queue_t * q;
unsigned long flags;
-
- q = get_queue(bh->b_dev);
- __make_request(q, major, rw, bh);
+ q = blk_get_queue(bh->b_rdev);
+
+ __make_request(q, rw, bh);
spin_lock_irqsave(&io_request_lock,flags);
- if( !q->plugged )
+ if (q && !q->plugged)
(q->request_fn)(q);
spin_unlock_irqrestore(&io_request_lock,flags);
}
-
/* This function can be used to request a number of buffers from a block
device. Currently the only restriction is that all buffers must belong to
the same device */
-void ll_rw_block(int rw, int nr, struct buffer_head * bh[])
+static void __ll_rw_block(int rw, int nr, struct buffer_head * bh[],int haslock)
{
unsigned int major;
int correct_size;
- request_queue_t * q;
- unsigned long flags;
+ request_queue_t *q;
int i;
-
major = MAJOR(bh[0]->b_dev);
- if (!(q = get_queue(bh[0]->b_dev))) {
+ q = blk_get_queue(bh[0]->b_dev);
+ if (!q) {
printk(KERN_ERR
"ll_rw_block: Trying to read nonexistent block-device %s (%ld)\n",
kdevname(bh[0]->b_dev), bh[0]->b_blocknr);
goto sorry;
}
- /* Determine correct block size for this device. */
+ /* Determine correct block size for this device. */
correct_size = BLOCK_SIZE;
if (blksize_size[major]) {
i = blksize_size[major][MINOR(bh[0]->b_dev)];
@@ -742,7 +760,7 @@
correct_size = i;
}
- /* Verify requested block sizes. */
+ /* Verify requested block sizes. */
for (i = 0; i < nr; i++) {
if (bh[i]->b_size != correct_size) {
printk(KERN_NOTICE "ll_rw_block: device %s: "
@@ -751,19 +769,6 @@
correct_size, bh[i]->b_size);
goto sorry;
}
-
- /* Md remaps blocks now */
- bh[i]->b_rdev = bh[i]->b_dev;
- bh[i]->b_rsector=bh[i]->b_blocknr*(bh[i]->b_size >> 9);
-#ifdef CONFIG_BLK_DEV_MD
- if (major==MD_MAJOR &&
- md_map (MINOR(bh[i]->b_dev), &bh[i]->b_rdev,
- &bh[i]->b_rsector, bh[i]->b_size >> 9)) {
- printk (KERN_ERR
- "Bad md_map in ll_rw_block\n");
- goto sorry;
- }
-#endif
}
if ((rw & WRITE) && is_read_only(bh[0]->b_dev)) {
@@ -773,25 +778,29 @@
}
for (i = 0; i < nr; i++) {
+ /* Only one thread can actually submit the I/O. */
+ if (haslock) {
+ if (!buffer_locked(bh[i]))
+ BUG();
+ } else {
+ if (test_and_set_bit(BH_Lock, &bh[i]->b_state))
+ continue;
+ }
set_bit(BH_Req, &bh[i]->b_state);
-#ifdef CONFIG_BLK_DEV_MD
- if (MAJOR(bh[i]->b_dev) == MD_MAJOR) {
- md_make_request(MINOR (bh[i]->b_dev), rw, bh[i]);
- continue;
+
+ if (q->make_request_fn)
+ q->make_request_fn(rw, bh[i]);
+ else {
+ bh[i]->b_rdev = bh[i]->b_dev;
+ bh[i]->b_rsector = bh[i]->b_blocknr*(bh[i]->b_size>>9);
+
+ generic_make_request(rw, bh[i]);
}
-#endif
- __make_request(q, MAJOR(bh[i]->b_rdev), rw, bh[i]);
}
- spin_lock_irqsave(&io_request_lock,flags);
- if( !q->plugged )
- {
- (q->request_fn)(q);
- }
- spin_unlock_irqrestore(&io_request_lock,flags);
return;
- sorry:
+sorry:
for (i = 0; i < nr; i++) {
mark_buffer_clean(bh[i]); /* remeber to refile it */
clear_bit(BH_Uptodate, &bh[i]->b_state);
@@ -800,8 +809,18 @@
return;
}
+void ll_rw_block(int rw, int nr, struct buffer_head * bh[])
+{
+ __ll_rw_block(rw, nr, bh, 0);
+}
+
+void ll_rw_block_locked(int rw, int nr, struct buffer_head * bh[])
+{
+ __ll_rw_block(rw, nr, bh, 1);
+}
+
#ifdef CONFIG_STRAM_SWAP
-extern int stram_device_init( void );
+extern int stram_device_init (void);
#endif
/*
@@ -811,8 +830,7 @@
* 1 means we are done
*/
-int
-end_that_request_first( struct request *req, int uptodate, char *name )
+int end_that_request_first (struct request *req, int uptodate, char *name)
{
struct buffer_head * bh;
int nsect;
@@ -847,8 +865,7 @@
return 0;
}
-void
-end_that_request_last( struct request *req )
+void end_that_request_last(struct request *req)
{
if (req->sem != NULL)
up(req->sem);
@@ -862,7 +879,7 @@
struct blk_dev_struct *dev;
for (dev = blk_dev + MAX_BLKDEV; dev-- != blk_dev;) {
- dev->queue = NULL;
+ dev->queue = NULL;
blk_init_queue(&dev->request_queue, NULL);
}
@@ -923,8 +940,8 @@
floppy_init();
#else
#if !defined (__mc68000__) && !defined(CONFIG_PPC) && !defined(__sparc__)\
- && !defined(CONFIG_APUS) && !defined(__sh__)
- outb_p(0xc, 0x3f2);
+ && !defined(CONFIG_APUS) && !defined(__sh__) && !defined(__ia64__)
+ outb_p(0xc, 0x3f2); /* XXX do something with the floppy controller?? */
#endif
#endif
#ifdef CONFIG_CDU31A
@@ -943,7 +960,7 @@
sbpcd_init();
#endif CONFIG_SBPCD
#ifdef CONFIG_AZTCD
- aztcd_init();
+ aztcd_init();
#endif CONFIG_AZTCD
#ifdef CONFIG_CDU535
sony535_init();
@@ -981,3 +998,5 @@
EXPORT_SYMBOL(blk_init_queue);
EXPORT_SYMBOL(blk_cleanup_queue);
EXPORT_SYMBOL(blk_queue_headactive);
+EXPORT_SYMBOL(blk_queue_pluggable);
+EXPORT_SYMBOL(generic_make_request);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)