root/kernel/blk_drv/ll_rw_blk.c

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

DEFINITIONS

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

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

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