root/fs/block_dev.c

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

DEFINITIONS

This source file includes following definitions.
  1. block_write
  2. block_read
  3. block_fsync

   1 /*
   2  *  linux/fs/block_dev.c
   3  *
   4  *  Copyright (C) 1991, 1992  Linus Torvalds
   5  */
   6 
   7 #include <linux/errno.h>
   8 #include <linux/sched.h>
   9 #include <linux/kernel.h>
  10 #include <linux/locks.h>
  11 #include <linux/fcntl.h>
  12 #include <asm/segment.h>
  13 #include <asm/system.h>
  14 
  15 extern int *blk_size[];
  16 extern int *blksize_size[];
  17 
  18 #define NBUF 64
  19 
  20 int block_write(struct inode * inode, struct file * filp, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
  21 {
  22         int blocksize, blocksize_bits, i, j, buffercount,write_error;
  23         int block, blocks;
  24         loff_t offset;
  25         int chars;
  26         int written = 0;
  27         int cluster_list[8];
  28         struct buffer_head * bhlist[NBUF];
  29         int blocks_per_cluster;
  30         unsigned int size;
  31         unsigned int dev;
  32         struct buffer_head * bh, *bufferlist[NBUF];
  33         register char * p;
  34         int excess;
  35 
  36         write_error = buffercount = 0;
  37         dev = inode->i_rdev;
  38         if ( is_read_only( inode->i_rdev ))
  39                 return -EPERM;
  40         blocksize = BLOCK_SIZE;
  41         if (blksize_size[MAJOR(dev)] && blksize_size[MAJOR(dev)][MINOR(dev)])
  42                 blocksize = blksize_size[MAJOR(dev)][MINOR(dev)];
  43 
  44         i = blocksize;
  45         blocksize_bits = 0;
  46         while(i != 1) {
  47                 blocksize_bits++;
  48                 i >>= 1;
  49         }
  50 
  51         blocks_per_cluster = PAGE_SIZE / blocksize;
  52 
  53         block = filp->f_pos >> blocksize_bits;
  54         offset = filp->f_pos & (blocksize-1);
  55 
  56         if (blk_size[MAJOR(dev)])
  57                 size = ((loff_t) blk_size[MAJOR(dev)][MINOR(dev)] << BLOCK_SIZE_BITS) >> blocksize_bits;
  58         else
  59                 size = INT_MAX;
  60         while (count>0) {
  61                 if (block >= size)
  62                         return written;
  63                 chars = blocksize - offset;
  64                 if (chars > count)
  65                         chars=count;
  66 
  67 #if 0
  68                 if (chars == blocksize)
  69                         bh = getblk(dev, block, blocksize);
  70                 else
  71                         bh = breada(dev,block,block+1,block+2,-1);
  72 
  73 #else
  74                 for(i=0; i<blocks_per_cluster; i++) cluster_list[i] = block+i;
  75                 if((block % blocks_per_cluster) == 0)
  76                   generate_cluster(dev, cluster_list, blocksize);
  77                 bh = getblk(dev, block, blocksize);
  78 
  79                 if (chars != blocksize && !bh->b_uptodate) {
  80                   if(!filp->f_reada ||
  81                      !read_ahead[MAJOR(dev)]) {
  82                     /* We do this to force the read of a single buffer */
  83                     brelse(bh);
  84                     bh = bread(dev,block,blocksize);
  85                   } else {
  86                     /* Read-ahead before write */
  87                     blocks = read_ahead[MAJOR(dev)] / (blocksize >> 9) / 2;
  88                     if (block + blocks > size) blocks = size - block;
  89                     if (blocks > NBUF) blocks=NBUF;
  90                     excess = (block + blocks) % blocks_per_cluster;
  91                     if ( blocks > excess )
  92                         blocks -= excess;
  93                     bhlist[0] = bh;
  94                     for(i=1; i<blocks; i++){
  95                       if(((i+block) % blocks_per_cluster) == 0) {
  96                         for(j=0; j<blocks_per_cluster; j++) cluster_list[j] = block+i+j;
  97                         generate_cluster(dev, cluster_list, blocksize);
  98                       };
  99                       bhlist[i] = getblk (dev, block+i, blocksize);
 100                       if(!bhlist[i]){
 101                         while(i >= 0) brelse(bhlist[i--]);
 102                         return written? written: -EIO;
 103                       };
 104                     };
 105                     ll_rw_block(READ, blocks, bhlist);
 106                     for(i=1; i<blocks; i++) brelse(bhlist[i]);
 107                     wait_on_buffer(bh);
 108                       
 109                   };
 110                 };
 111 #endif
 112                 block++;
 113                 if (!bh)
 114                         return written?written:-EIO;
 115                 p = offset + bh->b_data;
 116                 offset = 0;
 117                 filp->f_pos += chars;
 118                 written += chars;
 119                 count -= chars;
 120                 memcpy_fromfs(p,buf,chars);
 121                 p += chars;
 122                 buf += chars;
 123                 bh->b_uptodate = 1;
 124                 mark_buffer_dirty(bh, 0);
 125                 if (filp->f_flags & O_SYNC)
 126                         bufferlist[buffercount++] = bh;
 127                 else
 128                         brelse(bh);
 129                 if (buffercount == NBUF){
 130                         ll_rw_block(WRITE, buffercount, bufferlist);
 131                         for(i=0; i<buffercount; i++){
 132                                 wait_on_buffer(bufferlist[i]);
 133                                 if (!bufferlist[i]->b_uptodate)
 134                                         write_error=1;
 135                                 brelse(bufferlist[i]);
 136                         }
 137                         buffercount=0;
 138                 }
 139                 if(write_error)
 140                         break;
 141         }
 142         if ( buffercount ){
 143                 ll_rw_block(WRITE, buffercount, bufferlist);
 144                 for(i=0; i<buffercount; i++){
 145                         wait_on_buffer(bufferlist[i]);
 146                         if (!bufferlist[i]->b_uptodate)
 147                                 write_error=1;
 148                         brelse(bufferlist[i]);
 149                 }
 150         }               
 151         filp->f_reada = 1;
 152         if(write_error)
 153                 return -EIO;
 154         return written;
 155 }
 156 
 157 int block_read(struct inode * inode, struct file * filp, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 158 {
 159         unsigned int block;
 160         loff_t offset;
 161         int blocksize;
 162         int blocksize_bits, i;
 163         unsigned int blocks, rblocks, left;
 164         int bhrequest, uptodate;
 165         int cluster_list[8];
 166         int blocks_per_cluster;
 167         struct buffer_head ** bhb, ** bhe;
 168         struct buffer_head * buflist[NBUF];
 169         struct buffer_head * bhreq[NBUF];
 170         unsigned int chars;
 171         loff_t size;
 172         unsigned int dev;
 173         int read;
 174         int excess;
 175 
 176         dev = inode->i_rdev;
 177         blocksize = BLOCK_SIZE;
 178         if (blksize_size[MAJOR(dev)] && blksize_size[MAJOR(dev)][MINOR(dev)])
 179                 blocksize = blksize_size[MAJOR(dev)][MINOR(dev)];
 180         i = blocksize;
 181         blocksize_bits = 0;
 182         while (i != 1) {
 183                 blocksize_bits++;
 184                 i >>= 1;
 185         }
 186 
 187         offset = filp->f_pos;
 188         if (blk_size[MAJOR(dev)])
 189                 size = (loff_t) blk_size[MAJOR(dev)][MINOR(dev)] << BLOCK_SIZE_BITS;
 190         else
 191                 size = INT_MAX;
 192 
 193         blocks_per_cluster = PAGE_SIZE / blocksize;
 194 
 195         if (offset > size)
 196                 left = 0;
 197         else
 198                 left = size - offset;
 199         if (left > count)
 200                 left = count;
 201         if (left <= 0)
 202                 return 0;
 203         read = 0;
 204         block = offset >> blocksize_bits;
 205         offset &= blocksize-1;
 206         size >>= blocksize_bits;
 207         rblocks = blocks = (left + offset + blocksize - 1) >> blocksize_bits;
 208         bhb = bhe = buflist;
 209         if (filp->f_reada) {
 210                 if (blocks < read_ahead[MAJOR(dev)] / (blocksize >> 9))
 211                         blocks = read_ahead[MAJOR(dev)] / (blocksize >> 9);
 212                 excess = (block + blocks) % blocks_per_cluster;
 213                 if ( blocks > excess )
 214                         blocks -= excess;               
 215                 if (rblocks > blocks)
 216                         blocks = rblocks;
 217                 
 218         }
 219         if (block + blocks > size)
 220                 blocks = size - block;
 221 
 222         /* We do this in a two stage process.  We first try and request
 223            as many blocks as we can, then we wait for the first one to
 224            complete, and then we try and wrap up as many as are actually
 225            done.  This routine is rather generic, in that it can be used
 226            in a filesystem by substituting the appropriate function in
 227            for getblk.
 228 
 229            This routine is optimized to make maximum use of the various
 230            buffers and caches. */
 231 
 232         do {
 233                 bhrequest = 0;
 234                 uptodate = 1;
 235                 while (blocks) {
 236                         --blocks;
 237 #if 1
 238                         if((block % blocks_per_cluster) == 0) {
 239                           for(i=0; i<blocks_per_cluster; i++) cluster_list[i] = block+i;
 240                           generate_cluster(dev, cluster_list, blocksize);
 241                         }
 242 #endif
 243                         *bhb = getblk(dev, block++, blocksize);
 244                         if (*bhb && !(*bhb)->b_uptodate) {
 245                                 uptodate = 0;
 246                                 bhreq[bhrequest++] = *bhb;
 247                         }
 248 
 249                         if (++bhb == &buflist[NBUF])
 250                                 bhb = buflist;
 251 
 252                         /* If the block we have on hand is uptodate, go ahead
 253                            and complete processing. */
 254                         if (uptodate)
 255                                 break;
 256                         if (bhb == bhe)
 257                                 break;
 258                 }
 259 
 260                 /* Now request them all */
 261                 if (bhrequest) {
 262                         ll_rw_block(READ, bhrequest, bhreq);
 263                         refill_freelist(blocksize);
 264                 }
 265 
 266                 do { /* Finish off all I/O that has actually completed */
 267                         if (*bhe) {
 268                                 wait_on_buffer(*bhe);
 269                                 if (!(*bhe)->b_uptodate) {      /* read error? */
 270                                         brelse(*bhe);
 271                                         if (++bhe == &buflist[NBUF])
 272                                           bhe = buflist;
 273                                         left = 0;
 274                                         break;
 275                                 }
 276                         }                       
 277                         if (left < blocksize - offset)
 278                                 chars = left;
 279                         else
 280                                 chars = blocksize - offset;
 281                         filp->f_pos += chars;
 282                         left -= chars;
 283                         read += chars;
 284                         if (*bhe) {
 285                                 memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
 286                                 brelse(*bhe);
 287                                 buf += chars;
 288                         } else {
 289                                 while (chars-->0)
 290                                         put_fs_byte(0,buf++);
 291                         }
 292                         offset = 0;
 293                         if (++bhe == &buflist[NBUF])
 294                                 bhe = buflist;
 295                 } while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock));
 296         } while (left > 0);
 297 
 298 /* Release the read-ahead blocks */
 299         while (bhe != bhb) {
 300                 brelse(*bhe);
 301                 if (++bhe == &buflist[NBUF])
 302                         bhe = buflist;
 303         };
 304         if (!read)
 305                 return -EIO;
 306         filp->f_reada = 1;
 307         return read;
 308 }
 309 
 310 int block_fsync(struct inode *inode, struct file *filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 311 {
 312         return fsync_dev (inode->i_rdev);
 313 }

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