root/fs/ext2/file.c

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

DEFINITIONS

This source file includes following definitions.
  1. ext2_file_read
  2. ext2_file_write

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

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