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                                         brelse(*bhe);
 159                                         if (++bhe == &buflist[NBUF])
 160                                           bhe = buflist;
 161                                         left = 0;
 162                                         break;
 163                                 }
 164                         }
 165                         if (left < sb->s_blocksize - offset)
 166                                 chars = left;
 167                         else
 168                                 chars = sb->s_blocksize - offset;
 169                         filp->f_pos += chars;
 170                         left -= chars;
 171                         read += chars;
 172                         if (*bhe) {
 173                                 memcpy_tofs (buf, offset + (*bhe)->b_data,
 174                                              chars);
 175                                 brelse (*bhe);
 176                                 buf += chars;
 177                         } else {
 178                                 while (chars-- > 0)
 179                                         put_fs_byte (0, buf++);
 180                         }
 181                         offset = 0;
 182                         if (++bhe == &buflist[NBUF])
 183                                 bhe = buflist;
 184                 } while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock));
 185         } while (left > 0);
 186 
 187         /* Release the read-ahead blocks */
 188         while (bhe != bhb) {
 189                 brelse (*bhe);
 190                 if (++bhe == &buflist[NBUF])
 191                         bhe = buflist;
 192         }
 193         if (!read)
 194                 return -EIO;
 195         filp->f_reada = 1;
 196         if (!IS_RDONLY(inode)) {
 197                 inode->i_atime = CURRENT_TIME;
 198                 inode->i_dirt = 1;
 199         }
 200         return read;
 201 }
 202 
 203 static int ext2_file_write (struct inode * inode, struct file * filp,
     /* [previous][next][first][last][top][bottom][index][help] */
 204                             char * buf, int count)
 205 {
 206         off_t pos;
 207         int written, c;
 208         struct buffer_head * bh;
 209         char * p;
 210         struct super_block * sb;
 211         int err;
 212 
 213         if (!inode) {
 214                 printk("ext2_file_write: inode = NULL\n");
 215                 return -EINVAL;
 216         }
 217         sb = inode->i_sb;
 218         if (!S_ISREG(inode->i_mode)) {
 219                 printk ("ext2_file_write: mode = %07o\n", inode->i_mode);
 220                 return -EINVAL;
 221         }
 222 /*
 223  * ok, append may not work when many processes are writing at the same time
 224  * but so what. That way leads to madness anyway.
 225  */
 226         if (filp->f_flags & O_APPEND)
 227                 pos = inode->i_size;
 228         else
 229                 pos = filp->f_pos;
 230         written = 0;
 231         while (written < count) {
 232                 bh = ext2_getblk (inode, pos / sb->s_blocksize, 1, &err);
 233                 if (!bh) {
 234                         if (!written)
 235                                 written = err;
 236                         break;
 237                 }
 238                 c = sb->s_blocksize - (pos % sb->s_blocksize);
 239                 if (c > count-written)
 240                         c = count - written;
 241                 if (c != sb->s_blocksize && !bh->b_uptodate) {
 242                         ll_rw_block (READ, 1, &bh);
 243                         wait_on_buffer (bh);
 244                         if (!bh->b_uptodate) {
 245                                 brelse (bh);
 246                                 if (!written)
 247                                         written = -EIO;
 248                                 break;
 249                         }
 250                 }
 251                 p = (pos % sb->s_blocksize) + bh->b_data;
 252                 pos += c;
 253                 if (pos > inode->i_size) {
 254                         inode->i_size = pos;
 255                         inode->i_dirt = 1;
 256                 }
 257                 written += c;
 258                 memcpy_fromfs (p, buf, c);
 259                 buf += c;
 260                 bh->b_uptodate = 1;
 261                 bh->b_dirt = 1;
 262                 brelse (bh);
 263         }
 264         inode->i_mtime = CURRENT_TIME;
 265         inode->i_ctime = CURRENT_TIME;
 266         filp->f_pos = pos;
 267         inode->i_dirt = 1;
 268         return written;
 269 }

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