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

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