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

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