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         NULL,                   /* ioctl - default */
  48         NULL,                   /* mmap */
  49         NULL,                   /* no special open is needed */
  50         NULL,                   /* release */
  51         NULL                    /* 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         NULL                    /* 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 
  84         if (!inode) {
  85                 printk ("ext2_file_read: inode = NULL\n");
  86                 return -EINVAL;
  87         }
  88         sb = inode->i_sb;
  89         if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) {
  90                 printk ("ext2_file_read: mode = %07o\n", inode->i_mode);
  91                 return -EINVAL;
  92         }
  93         offset = filp->f_pos;
  94         size = inode->i_size;
  95         if (offset > size)
  96                 left = 0;
  97         else
  98                 left = size - offset;
  99         if (left > count)
 100                 left = count;
 101         if (left <= 0)
 102                 return 0;
 103         read = 0;
 104         block = offset >> EXT2_BLOCK_SIZE_BITS(sb);
 105         offset &= (sb->s_blocksize - 1);
 106         size = (size + sb->s_blocksize - 1) >> EXT2_BLOCK_SIZE_BITS(sb);
 107         blocks = (left + offset + sb->s_blocksize - 1) >> EXT2_BLOCK_SIZE_BITS(sb);
 108         bhb = bhe = buflist;
 109         if (filp->f_reada) {
 110                 blocks += read_ahead[MAJOR(inode->i_dev)] / (BLOCK_SIZE >> 9);
 111                 if (block + blocks > size)
 112                         blocks = size - block;
 113         }
 114 
 115         /* We do this in a two stage process.  We first try and request
 116            as many blocks as we can, then we wait for the first one to
 117            complete, and then we try and wrap up as many as are actually
 118            done.  This routine is rather generic, in that it can be used
 119            in a filesystem by substituting the appropriate function in
 120            for getblk
 121 
 122            This routine is optimized to make maximum use of the various
 123            buffers and caches. */
 124 
 125         do {
 126                 bhrequest = 0;
 127                 uptodate = 1;
 128                 while (blocks) {
 129                         --blocks;
 130                         *bhb = ext2_getblk (inode, block++, 0);
 131                         if (*bhb && !(*bhb)->b_uptodate) {
 132                                 uptodate = 0;
 133                                 bhreq[bhrequest++] = *bhb;
 134                         }
 135 
 136                         if (++bhb == &buflist[NBUF])
 137                                 bhb = buflist;
 138 
 139                         /* If the block we have on hand is uptodate, go ahead
 140                            and complete processing */
 141                         if (uptodate)
 142                                 break;
 143 
 144                         if (bhb == bhe)
 145                                 break;
 146                 }
 147 
 148                 /* Now request them all */
 149                 if (bhrequest)
 150                         ll_rw_block (READ, bhrequest, bhreq);
 151 
 152                 do { /* Finish off all I/O that has actually completed */
 153                         if (*bhe) {
 154                                 wait_on_buffer (*bhe);
 155                                 if (!(*bhe)->b_uptodate) { /* read error? */
 156                                         left = 0;
 157                                         break;
 158                                 }
 159                         }
 160                         if (left < sb->s_blocksize - offset)
 161                                 chars = left;
 162                         else
 163                                 chars = sb->s_blocksize - offset;
 164                         filp->f_pos += chars;
 165                         left -= chars;
 166                         read += chars;
 167                         if (*bhe) {
 168                                 memcpy_tofs (buf, offset + (*bhe)->b_data,
 169                                              chars);
 170                                 brelse (*bhe);
 171                                 buf += chars;
 172                         } else {
 173                                 while (chars-- > 0)
 174                                         put_fs_byte (0, buf++);
 175                         }
 176                         offset = 0;
 177                         if (++bhe == &buflist[NBUF])
 178                                 bhe = buflist;
 179                 } while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock));
 180         } while (left > 0);
 181 
 182         /* Release the read-ahead blocks */
 183         while (bhe != bhb) {
 184                 brelse (*bhe);
 185                 if (++bhe == &buflist[NBUF])
 186                         bhe = buflist;
 187         }
 188         if (!read)
 189                 return -EIO;
 190         filp->f_reada = 1;
 191         if (!IS_RDONLY(inode)) {
 192                 inode->i_atime = CURRENT_TIME;
 193                 inode->i_dirt = 1;
 194         }
 195         return read;
 196 }
 197 
 198 static int ext2_file_write (struct inode * inode, struct file * filp,
     /* [previous][next][first][last][top][bottom][index][help] */
 199                             char * buf, int count)
 200 {
 201         off_t pos;
 202         int written, c;
 203         struct buffer_head * bh;
 204         char * p;
 205         struct super_block * sb;
 206 
 207         if (!inode) {
 208                 printk("ext2_file_write: inode = NULL\n");
 209                 return -EINVAL;
 210         }
 211         sb = inode->i_sb;
 212         if (!S_ISREG(inode->i_mode)) {
 213                 printk ("ext2_file_write: mode = %07o\n", inode->i_mode);
 214                 return -EINVAL;
 215         }
 216 /*
 217  * ok, append may not work when many processes are writing at the same time
 218  * but so what. That way leads to madness anyway.
 219  */
 220         if (filp->f_flags & O_APPEND)
 221                 pos = inode->i_size;
 222         else
 223                 pos = filp->f_pos;
 224         written = 0;
 225         while (written < count) {
 226                 bh = ext2_getblk (inode, pos / sb->s_blocksize, 1);
 227                 if (!bh) {
 228 #ifdef EXT2FS_DEBUG
 229                         printk ("ext2_file_write: ext2_getblk returned NULL\n");
 230 #endif
 231                         if (!written)
 232                                 written = -ENOSPC;
 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] */