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

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