root/fs/ext/file.c

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

DEFINITIONS

This source file includes following definitions.
  1. ext_file_read
  2. ext_file_write

   1 /*
   2  *  linux/fs/ext/file.c
   3  *
   4  *  Copyright (C) 1992 Remy Card (card@masi.ibp.fr)
   5  *
   6  *  from
   7  *
   8  *  linux/fs/minix/file.c
   9  *
  10  *  Copyright (C) 1991, 1992 Linus Torvalds
  11  *
  12  *  ext regular file handling primitives
  13  */
  14 
  15 #include <asm/segment.h>
  16 #include <asm/system.h>
  17 
  18 #include <linux/sched.h>
  19 #include <linux/ext_fs.h>
  20 #include <linux/kernel.h>
  21 #include <linux/errno.h>
  22 #include <linux/fcntl.h>
  23 #include <linux/stat.h>
  24 #include <linux/locks.h>
  25 
  26 #define NBUF    16
  27 
  28 #define MIN(a,b) (((a)<(b))?(a):(b))
  29 #define MAX(a,b) (((a)>(b))?(a):(b))
  30 
  31 #include <linux/fs.h>
  32 #include <linux/ext_fs.h>
  33 
  34 static int ext_file_read(struct inode *, struct file *, char *, int);
  35 static int ext_file_write(struct inode *, struct file *, char *, int);
  36 
  37 /*
  38  * We have mostly NULL's here: the current defaults are ok for
  39  * the ext filesystem.
  40  */
  41 static struct file_operations ext_file_operations = {
  42         NULL,                   /* lseek - default */
  43         ext_file_read,  /* read */
  44         ext_file_write, /* write */
  45         NULL,                   /* readdir - bad */
  46         NULL,                   /* select - default */
  47         NULL,                   /* ioctl - default */
  48         NULL,                   /* mmap */
  49         NULL,                   /* no special open is needed */
  50         NULL                    /* release */
  51 };
  52 
  53 struct inode_operations ext_file_inode_operations = {
  54         &ext_file_operations,   /* default file operations */
  55         NULL,                   /* create */
  56         NULL,                   /* lookup */
  57         NULL,                   /* link */
  58         NULL,                   /* unlink */
  59         NULL,                   /* symlink */
  60         NULL,                   /* mkdir */
  61         NULL,                   /* rmdir */
  62         NULL,                   /* mknod */
  63         NULL,                   /* rename */
  64         NULL,                   /* readlink */
  65         NULL,                   /* follow_link */
  66         ext_bmap,               /* bmap */
  67         ext_truncate,           /* truncate */
  68         NULL                    /* permission */
  69 };
  70 
  71 static int ext_file_read(struct inode * inode, struct file * filp, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
  72 {
  73         int read,left,chars;
  74         int block, blocks, offset;
  75         int bhrequest, uptodate;
  76         struct buffer_head ** bhb, ** bhe;
  77         struct buffer_head * bhreq[NBUF];
  78         struct buffer_head * buflist[NBUF];
  79         unsigned int size;
  80 
  81         if (!inode) {
  82                 printk("ext_file_read: inode = NULL\n");
  83                 return -EINVAL;
  84         }
  85         if (!S_ISREG(inode->i_mode)) {
  86                 printk("ext_file_read: mode = %07o\n",inode->i_mode);
  87                 return -EINVAL;
  88         }
  89         offset = filp->f_pos;
  90         size = inode->i_size;
  91         if (offset > size)
  92                 left = 0;
  93         else
  94                 left = size - offset;
  95         if (left > count)
  96                 left = count;
  97         if (left <= 0)
  98                 return 0;
  99         read = 0;
 100         block = offset >> BLOCK_SIZE_BITS;
 101         offset &= BLOCK_SIZE-1;
 102         size = (size + (BLOCK_SIZE-1)) >> BLOCK_SIZE_BITS;
 103         blocks = (left + offset + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS;
 104         bhb = bhe = buflist;
 105         if (filp->f_reada) {
 106                 blocks += read_ahead[MAJOR(inode->i_dev)] / (BLOCK_SIZE >> 9);
 107                 if (block + blocks > size)
 108                         blocks = size - block;
 109         }
 110 
 111         /* We do this in a two stage process.  We first try and request
 112            as many blocks as we can, then we wait for the first one to
 113            complete, and then we try and wrap up as many as are actually
 114            done.  This routine is rather generic, in that it can be used
 115            in a filesystem by substituting the appropriate function in
 116            for getblk.
 117 
 118            This routine is optimized to make maximum use of the various
 119            buffers and caches. */
 120 
 121         do {
 122                 bhrequest = 0;
 123                 uptodate = 1;
 124                 while (blocks) {
 125                         --blocks;
 126                         *bhb = ext_getblk(inode, block++, 0);
 127                         if (*bhb && !(*bhb)->b_uptodate) {
 128                                 uptodate = 0;
 129                                 bhreq[bhrequest++] = *bhb;
 130                         }
 131 
 132                         if (++bhb == &buflist[NBUF])
 133                                 bhb = buflist;
 134 
 135                         /* If the block we have on hand is uptodate, go ahead
 136                            and complete processing. */
 137                         if (uptodate)
 138                                 break;
 139                         if (bhb == bhe)
 140                                 break;
 141                 }
 142 
 143                 /* Now request them all */
 144                 if (bhrequest)
 145                         ll_rw_block(READ, bhrequest, bhreq);
 146 
 147                 do { /* Finish off all I/O that has actually completed */
 148                         if (*bhe) {
 149                                 wait_on_buffer(*bhe);
 150                                 if (!(*bhe)->b_uptodate) {      /* read error? */
 151                                         left = 0;
 152                                         break;
 153                                 }
 154                         }
 155                         if (left < BLOCK_SIZE - offset)
 156                                 chars = left;
 157                         else
 158                                 chars = BLOCK_SIZE - offset;
 159                         filp->f_pos += chars;
 160                         left -= chars;
 161                         read += chars;
 162                         if (*bhe) {
 163                                 memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
 164                                 brelse(*bhe);
 165                                 buf += chars;
 166                         } else {
 167                                 while (chars-->0)
 168                                         put_fs_byte(0,buf++);
 169                         }
 170                         offset = 0;
 171                         if (++bhe == &buflist[NBUF])
 172                                 bhe = buflist;
 173                 } while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock));
 174         } while (left > 0);
 175 
 176 /* Release the read-ahead blocks */
 177         while (bhe != bhb) {
 178                 brelse(*bhe);
 179                 if (++bhe == &buflist[NBUF])
 180                         bhe = buflist;
 181         };
 182         if (!read)
 183                 return -EIO;
 184         filp->f_reada = 1;
 185         if (!IS_RDONLY(inode)) {
 186                 inode->i_atime = CURRENT_TIME;
 187                 inode->i_dirt = 1;
 188         }
 189         return read;
 190 }
 191 
 192 static int ext_file_write(struct inode * inode, struct file * filp, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 193 {
 194         off_t pos;
 195         int written,c;
 196         struct buffer_head * bh;
 197         char * p;
 198 
 199         if (!inode) {
 200                 printk("ext_file_write: inode = NULL\n");
 201                 return -EINVAL;
 202         }
 203         if (!S_ISREG(inode->i_mode)) {
 204                 printk("ext_file_write: mode = %07o\n",inode->i_mode);
 205                 return -EINVAL;
 206         }
 207 /*
 208  * ok, append may not work when many processes are writing at the same time
 209  * but so what. That way leads to madness anyway.
 210  */
 211         if (filp->f_flags & O_APPEND)
 212                 pos = inode->i_size;
 213         else
 214                 pos = filp->f_pos;
 215         written = 0;
 216         while (written<count) {
 217                 bh = ext_getblk(inode,pos/BLOCK_SIZE,1);
 218                 if (!bh) {
 219                         if (!written)
 220                                 written = -ENOSPC;
 221                         break;
 222                 }
 223                 c = BLOCK_SIZE - (pos % BLOCK_SIZE);
 224                 if (c > count-written)
 225                         c = count-written;
 226                 if (c != BLOCK_SIZE && !bh->b_uptodate) {
 227                         ll_rw_block(READ, 1, &bh);
 228                         wait_on_buffer(bh);
 229                         if (!bh->b_uptodate) {
 230                                 brelse(bh);
 231                                 if (!written)
 232                                         written = -EIO;
 233                                 break;
 234                         }
 235                 }
 236                 p = (pos % BLOCK_SIZE) + bh->b_data;
 237                 pos += c;
 238                 if (pos > inode->i_size) {
 239                         inode->i_size = pos;
 240                         inode->i_dirt = 1;
 241                 }
 242                 written += c;
 243                 memcpy_fromfs(p,buf,c);
 244                 buf += c;
 245                 bh->b_uptodate = 1;
 246                 bh->b_dirt = 1;
 247                 brelse(bh);
 248         }
 249         inode->i_mtime = CURRENT_TIME;
 250         inode->i_ctime = CURRENT_TIME;
 251         filp->f_pos = pos;
 252         inode->i_dirt = 1;
 253         return written;
 254 }

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