root/kernel/blk_drv/ll_rw_blk.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. is_read_only
  2. set_device_ro
  3. add_request
  4. make_request
  5. ll_rw_page
  6. ll_rw_block
  7. ll_rw_swap_file
  8. blk_dev_init

   1 /*
   2  *  linux/kernel/blk_dev/ll_rw.c
   3  *
   4  * Copyright (C) 1991, 1992 Linus Torvalds
   5  */
   6 
   7 /*
   8  * This handles all read/write requests to block devices
   9  */
  10 #include <linux/sched.h>
  11 #include <linux/kernel.h>
  12 #include <linux/errno.h>
  13 #include <linux/string.h>
  14 #include <linux/config.h>
  15 #include <linux/locks.h>
  16 
  17 #include <asm/system.h>
  18 
  19 #include "blk.h"
  20 
  21 extern long rd_init(long mem_start, int length);
  22 
  23 /*
  24  * The request-struct contains all necessary data
  25  * to load a nr of sectors into memory
  26  */
  27 struct request request[NR_REQUEST];
  28 
  29 /*
  30  * used to wait on when there are no free requests
  31  */
  32 struct wait_queue * wait_for_request = NULL;
  33 
  34 /* blk_dev_struct is:
  35  *      do_request-address
  36  *      next-request
  37  */
  38 struct blk_dev_struct blk_dev[NR_BLK_DEV] = {
  39         { NULL, NULL },         /* no_dev */
  40         { NULL, NULL },         /* dev mem */
  41         { NULL, NULL },         /* dev fd */
  42         { NULL, NULL },         /* dev hd */
  43         { NULL, NULL },         /* dev ttyx */
  44         { NULL, NULL },         /* dev tty */
  45         { NULL, NULL },         /* dev lp */
  46         { NULL, NULL },         /* dev pipes */
  47         { NULL, NULL },         /* dev sd */
  48         { NULL, NULL }          /* dev st */
  49 };
  50 
  51 /*
  52  * blk_size contains the size of all block-devices:
  53  *
  54  * blk_size[MAJOR][MINOR]
  55  *
  56  * if (!blk_size[MAJOR]) then no minor size checking is done.
  57  */
  58 int * blk_size[NR_BLK_DEV] = { NULL, NULL, };
  59 
  60 /* RO fail safe mechanism */
  61 
  62 static long ro_bits[NR_BLK_DEV][8];
  63 
  64 int is_read_only(int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
  65 {
  66         int minor,major;
  67 
  68         major = MAJOR(dev);
  69         minor = MINOR(dev);
  70         if (major < 0 || major >= NR_BLK_DEV) return 0;
  71         return ro_bits[major][minor >> 5] & (1 << (minor & 31));
  72 }
  73 
  74 void set_device_ro(int dev,int flag)
     /* [previous][next][first][last][top][bottom][index][help] */
  75 {
  76         int minor,major;
  77 
  78         major = MAJOR(dev);
  79         minor = MINOR(dev);
  80         if (major < 0 || major >= NR_BLK_DEV) return;
  81         if (flag) ro_bits[major][minor >> 5] |= 1 << (minor & 31);
  82         else ro_bits[major][minor >> 5] &= ~(1 << (minor & 31));
  83 }
  84 
  85 /*
  86  * add-request adds a request to the linked list.
  87  * It disables interrupts so that it can muck with the
  88  * request-lists in peace.
  89  */
  90 static void add_request(struct blk_dev_struct * dev, struct request * req)
     /* [previous][next][first][last][top][bottom][index][help] */
  91 {
  92         struct request * tmp;
  93 
  94         req->next = NULL;
  95         cli();
  96         if (req->bh)
  97                 req->bh->b_dirt = 0;
  98         if (!(tmp = dev->current_request)) {
  99                 dev->current_request = req;
 100                 (dev->request_fn)();
 101                 sti();
 102                 return;
 103         }
 104         for ( ; tmp->next ; tmp = tmp->next) {
 105                 if ((IN_ORDER(tmp,req) ||
 106                     !IN_ORDER(tmp,tmp->next)) &&
 107                     IN_ORDER(req,tmp->next))
 108                         break;
 109         }
 110         req->next = tmp->next;
 111         tmp->next = req;
 112         sti();
 113 }
 114 
 115 static void make_request(int major,int rw, struct buffer_head * bh)
     /* [previous][next][first][last][top][bottom][index][help] */
 116 {
 117         unsigned int sector, count;
 118         struct request * req;
 119         int rw_ahead;
 120 
 121 /* WRITEA/READA is special case - it is not really needed, so if the */
 122 /* buffer is locked, we just forget about it, else it's a normal read */
 123         if (rw_ahead = (rw == READA || rw == WRITEA)) {
 124                 if (bh->b_lock)
 125                         return;
 126                 if (rw == READA)
 127                         rw = READ;
 128                 else
 129                         rw = WRITE;
 130         }
 131         if (rw!=READ && rw!=WRITE) {
 132                 printk("Bad block dev command, must be R/W/RA/WA\n");
 133                 return;
 134         }
 135         count = bh->b_size >> 9;
 136         sector = bh->b_blocknr * count;
 137         if (blk_size[major])
 138                 if (blk_size[major][MINOR(bh->b_dev)] < (sector + count)>>1) {
 139                         bh->b_dirt = bh->b_uptodate = 0;
 140                         return;
 141                 }
 142         lock_buffer(bh);
 143         if ((rw == WRITE && !bh->b_dirt) || (rw == READ && bh->b_uptodate)) {
 144                 unlock_buffer(bh);
 145                 return;
 146         }
 147 repeat:
 148         cli();
 149         if ((major == 3 ||  major == 8 || major == 11)&& (req = blk_dev[major].current_request)) {
 150                 while (req = req->next) {
 151                         if (req->dev == bh->b_dev &&
 152                             !req->waiting &&
 153                             req->cmd == rw &&
 154                             req->sector + req->nr_sectors == sector &&
 155                             req->nr_sectors < 254) {
 156                                 req->bhtail->b_reqnext = bh;
 157                                 req->bhtail = bh;
 158                                 req->nr_sectors += count;
 159                                 bh->b_dirt = 0;
 160                                 sti();
 161                                 return;
 162                         }
 163                 }
 164         }
 165 /* we don't allow the write-requests to fill up the queue completely:
 166  * we want some room for reads: they take precedence. The last third
 167  * of the requests are only for reads.
 168  */
 169         if (rw == READ)
 170                 req = request+NR_REQUEST;
 171         else
 172                 req = request+(NR_REQUEST/2);
 173 /* find an empty request */
 174         while (--req >= request)
 175                 if (req->dev < 0)
 176                         goto found;
 177 /* if none found, sleep on new requests: check for rw_ahead */
 178         if (rw_ahead) {
 179                 sti();
 180                 unlock_buffer(bh);
 181                 return;
 182         }
 183         sleep_on(&wait_for_request);
 184         sti();
 185         goto repeat;
 186 
 187 found:
 188 /* fill up the request-info, and add it to the queue */
 189         req->dev = bh->b_dev;
 190         sti();
 191         req->cmd = rw;
 192         req->errors = 0;
 193         req->sector = sector;
 194         req->nr_sectors = count;
 195         req->current_nr_sectors = count;
 196         req->buffer = bh->b_data;
 197         req->waiting = NULL;
 198         req->bh = bh;
 199         req->bhtail = bh;
 200         req->next = NULL;
 201         add_request(major+blk_dev,req);
 202 }
 203 
 204 void ll_rw_page(int rw, int dev, int page, char * buffer)
     /* [previous][next][first][last][top][bottom][index][help] */
 205 {
 206         struct request * req;
 207         unsigned int major = MAJOR(dev);
 208 
 209         if (major >= NR_BLK_DEV || !(blk_dev[major].request_fn)) {
 210                 printk("Trying to read nonexistent block-device %04x (%d)\n",dev,page*8);
 211                 return;
 212         }
 213         if (rw!=READ && rw!=WRITE)
 214                 panic("Bad block dev command, must be R/W");
 215         if (rw == WRITE && is_read_only(dev)) {
 216                 printk("Can't page to read-only device 0x%X\n\r",dev);
 217                 return;
 218         }
 219         cli();
 220 repeat:
 221         req = request+NR_REQUEST;
 222         while (--req >= request)
 223                 if (req->dev<0)
 224                         break;
 225         if (req < request) {
 226                 sleep_on(&wait_for_request);
 227                 goto repeat;
 228         }
 229         sti();
 230 /* fill up the request-info, and add it to the queue */
 231         req->dev = dev;
 232         req->cmd = rw;
 233         req->errors = 0;
 234         req->sector = page<<3;
 235         req->nr_sectors = 8;
 236         req->current_nr_sectors = 8;
 237         req->buffer = buffer;
 238         req->waiting = current;
 239         req->bh = NULL;
 240         req->next = NULL;
 241         current->state = TASK_UNINTERRUPTIBLE;
 242         add_request(major+blk_dev,req);
 243         schedule();
 244 }
 245 
 246 void ll_rw_block(int rw, struct buffer_head * bh)
     /* [previous][next][first][last][top][bottom][index][help] */
 247 {
 248         unsigned int major;
 249 
 250         if (!bh)
 251                 return;
 252         if (bh->b_size != 1024) {
 253                 printk("ll_rw_block: only 1024-char blocks implemented (%d)\n",bh->b_size);
 254                 bh->b_dirt = bh->b_uptodate = 0;
 255                 return;
 256         }
 257         if ((major=MAJOR(bh->b_dev)) >= NR_BLK_DEV ||
 258         !(blk_dev[major].request_fn)) {
 259                 printk("ll_rw_block: Trying to read nonexistent block-device %04x (%d)\n",bh->b_dev,bh->b_blocknr);
 260                 bh->b_dirt = bh->b_uptodate = 0;
 261                 return;
 262         }
 263         if ((rw == WRITE || rw == WRITEA) && is_read_only(bh->b_dev)) {
 264                 printk("Can't write to read-only device 0x%X\n\r",bh->b_dev);
 265                 bh->b_dirt = bh->b_uptodate = 0;
 266                 return;
 267         }
 268         make_request(major,rw,bh);
 269 }
 270 
 271 void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buf)
     /* [previous][next][first][last][top][bottom][index][help] */
 272 {
 273         int i;
 274         struct request * req;
 275         unsigned int major = MAJOR(dev);
 276 
 277         if (major >= NR_BLK_DEV || !(blk_dev[major].request_fn)) {
 278                 printk("ll_rw_swap_file: trying to swap nonexistent block-device\n\r");
 279                 return;
 280         }
 281 
 282         if (rw!=READ && rw!=WRITE) {
 283                 printk("ll_rw_swap: bad block dev command, must be R/W");
 284                 return;
 285         }
 286         if (rw == WRITE && is_read_only(dev)) {
 287                 printk("Can't swap to read-only device 0x%X\n\r",dev);
 288                 return;
 289         }
 290         
 291         for (i=0; i<nb; i++, buf += BLOCK_SIZE)
 292         {
 293 repeat:
 294                 req = request+NR_REQUEST;
 295                 while (--req >= request)
 296                         if (req->dev<0)
 297                                 break;
 298                 if (req < request) {
 299                         sleep_on(&wait_for_request);
 300                         goto repeat;
 301                 }
 302 
 303                 req->dev = dev;
 304                 req->cmd = rw;
 305                 req->errors = 0;
 306                 req->sector = b[i] << 1;
 307                 req->nr_sectors = 2;
 308                 req->current_nr_sectors = 2;
 309                 req->buffer = buf;
 310                 req->waiting = current;
 311                 req->bh = NULL;
 312                 req->next = NULL;
 313                 current->state = TASK_UNINTERRUPTIBLE;
 314                 add_request(major+blk_dev,req);
 315                 schedule();
 316         }
 317 }
 318 
 319 long blk_dev_init(long mem_start, long mem_end)
     /* [previous][next][first][last][top][bottom][index][help] */
 320 {
 321         int i;
 322 
 323         for (i=0 ; i<NR_REQUEST ; i++) {
 324                 request[i].dev = -1;
 325                 request[i].next = NULL;
 326         }
 327         memset(ro_bits,0,sizeof(ro_bits));
 328 #ifdef CONFIG_BLK_DEV_HD
 329         mem_start = hd_init(mem_start,mem_end);
 330 #endif
 331 #ifdef RAMDISK
 332         mem_start += rd_init(mem_start, RAMDISK*1024);
 333 #endif
 334         return mem_start;
 335 }

/* [previous][next][first][last][top][bottom][index][help] */