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
  3. ext2_release_file

   1 /*
   2  *  linux/fs/ext2/file.c
   3  *
   4  *  Copyright (C) 1992, 1993, 1994  Remy Card (card@masi.ibp.fr)
   5  *                                  Laboratoire MASI - Institut Blaise Pascal
   6  *                                  Universite Pierre et Marie Curie (Paris VI)
   7  *
   8  *  from
   9  *
  10  *  linux/fs/minix/file.c
  11  *
  12  *  Copyright (C) 1991, 1992  Linus Torvalds
  13  *
  14  *  ext2 fs regular file handling primitives
  15  */
  16 
  17 #include <asm/segment.h>
  18 #include <asm/system.h>
  19 
  20 #include <linux/errno.h>
  21 #include <linux/fs.h>
  22 #include <linux/ext2_fs.h>
  23 #include <linux/fcntl.h>
  24 #include <linux/sched.h>
  25 #include <linux/stat.h>
  26 #include <linux/locks.h>
  27 
  28 #define NBUF    32
  29 
  30 #define MIN(a,b) (((a)<(b))?(a):(b))
  31 #define MAX(a,b) (((a)>(b))?(a):(b))
  32 
  33 #include <linux/fs.h>
  34 #include <linux/ext2_fs.h>
  35 
  36 static int ext2_file_read (struct inode *, struct file *, char *, int);
  37 static int ext2_file_write (struct inode *, struct file *, char *, int);
  38 static void ext2_release_file (struct inode *, struct file *);
  39 
  40 /*
  41  * We have mostly NULL's here: the current defaults are ok for
  42  * the ext2 filesystem.
  43  */
  44 static struct file_operations ext2_file_operations = {
  45         NULL,                   /* lseek - default */
  46         ext2_file_read,         /* read */
  47         ext2_file_write,        /* write */
  48         NULL,                   /* readdir - bad */
  49         NULL,                   /* select - default */
  50         ext2_ioctl,             /* ioctl */
  51         generic_mmap,           /* mmap */
  52         NULL,                   /* no special open is needed */
  53         ext2_release_file,      /* release */
  54         ext2_sync_file,         /* fsync */
  55         NULL,                   /* fasync */
  56         NULL,                   /* check_media_change */
  57         NULL                    /* revalidate */
  58 };
  59 
  60 struct inode_operations ext2_file_inode_operations = {
  61         &ext2_file_operations,/* default file operations */
  62         NULL,                   /* create */
  63         NULL,                   /* lookup */
  64         NULL,                   /* link */
  65         NULL,                   /* unlink */
  66         NULL,                   /* symlink */
  67         NULL,                   /* mkdir */
  68         NULL,                   /* rmdir */
  69         NULL,                   /* mknod */
  70         NULL,                   /* rename */
  71         NULL,                   /* readlink */
  72         NULL,                   /* follow_link */
  73         ext2_bmap,              /* bmap */
  74         ext2_truncate,          /* truncate */
  75         ext2_permission,        /* permission */
  76         NULL                    /* smap */
  77 };
  78 
  79 static int ext2_file_read (struct inode * inode, struct file * filp,
     /* [previous][next][first][last][top][bottom][index][help] */
  80                     char * buf, int count)
  81 {
  82         int read, left, chars;
  83         int block, blocks, offset;
  84         int bhrequest, uptodate;
  85         int clusterblocks;
  86         struct buffer_head ** bhb, ** bhe;
  87         struct buffer_head * bhreq[NBUF];
  88         struct buffer_head * buflist[NBUF];
  89         struct super_block * sb;
  90         unsigned int size;
  91         int err;
  92 
  93         if (!inode) {
  94                 printk ("ext2_file_read: inode = NULL\n");
  95                 return -EINVAL;
  96         }
  97         sb = inode->i_sb;
  98         if (!S_ISREG(inode->i_mode)) {
  99                 ext2_warning (sb, "ext2_file_read", "mode = %07o",
 100                               inode->i_mode);
 101                 return -EINVAL;
 102         }
 103         offset = filp->f_pos;
 104         size = inode->i_size;
 105         if (offset > size)
 106                 left = 0;
 107         else
 108                 left = size - offset;
 109         if (left > count)
 110                 left = count;
 111         if (left <= 0)
 112                 return 0;
 113         read = 0;
 114         block = offset >> EXT2_BLOCK_SIZE_BITS(sb);
 115         offset &= (sb->s_blocksize - 1);
 116         size = (size + sb->s_blocksize - 1) >> EXT2_BLOCK_SIZE_BITS(sb);
 117         blocks = (left + offset + sb->s_blocksize - 1) >> EXT2_BLOCK_SIZE_BITS(sb);
 118         bhb = bhe = buflist;
 119         if (filp->f_reada) {
 120                 if (blocks < read_ahead[MAJOR(inode->i_dev)] >> (EXT2_BLOCK_SIZE_BITS(sb) - 9))
 121                     blocks = read_ahead[MAJOR(inode->i_dev)] >> (EXT2_BLOCK_SIZE_BITS(sb) - 9);
 122                 if (block + blocks > size)
 123                         blocks = size - block;
 124         }
 125 
 126         /*
 127          * We do this in a two stage process.  We first try and request
 128          * as many blocks as we can, then we wait for the first one to
 129          * complete, and then we try and wrap up as many as are actually
 130          * done.  This routine is rather generic, in that it can be used
 131          * in a filesystem by substituting the appropriate function in
 132          * for getblk
 133          *
 134          * This routine is optimized to make maximum use of the various
 135          * buffers and caches.
 136          */
 137 
 138         clusterblocks = 0;
 139 
 140         do {
 141                 bhrequest = 0;
 142                 uptodate = 1;
 143                 while (blocks) {
 144                         --blocks;
 145 #if 1
 146                         if(!clusterblocks) clusterblocks = ext2_getcluster(inode, block);
 147                         if(clusterblocks) clusterblocks--;
 148 #endif
 149 
 150                         *bhb = ext2_getblk (inode, block++, 0, &err);
 151                         if (*bhb && !(*bhb)->b_uptodate) {
 152                                 uptodate = 0;
 153                                 bhreq[bhrequest++] = *bhb;
 154                         }
 155 
 156                         if (++bhb == &buflist[NBUF])
 157                                 bhb = buflist;
 158 
 159                         /*
 160                          * If the block we have on hand is uptodate, go ahead
 161                          * and complete processing
 162                          */
 163                         if (uptodate)
 164                                 break;
 165 
 166                         if (bhb == bhe)
 167                                 break;
 168                 }
 169 
 170                 /*
 171                  * Now request them all
 172                  */
 173                 if (bhrequest)
 174                         ll_rw_block (READ, bhrequest, bhreq);
 175 
 176                 do {
 177                         /*
 178                          * Finish off all I/O that has actually completed
 179                          */
 180                         if (*bhe) {
 181                                 wait_on_buffer (*bhe);
 182                                 if (!(*bhe)->b_uptodate) { /* read error? */
 183                                         brelse(*bhe);
 184                                         if (++bhe == &buflist[NBUF])
 185                                           bhe = buflist;
 186                                         left = 0;
 187                                         break;
 188                                 }
 189                         }
 190                         if (left < sb->s_blocksize - offset)
 191                                 chars = left;
 192                         else
 193                                 chars = sb->s_blocksize - offset;
 194                         filp->f_pos += chars;
 195                         left -= chars;
 196                         read += chars;
 197                         if (*bhe) {
 198                                 memcpy_tofs (buf, offset + (*bhe)->b_data,
 199                                              chars);
 200                                 brelse (*bhe);
 201                                 buf += chars;
 202                         } else {
 203                                 while (chars-- > 0)
 204                                         put_fs_byte (0, buf++);
 205                         }
 206                         offset = 0;
 207                         if (++bhe == &buflist[NBUF])
 208                                 bhe = buflist;
 209                 } while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock));
 210         } while (left > 0);
 211 
 212         /*
 213          * Release the read-ahead blocks
 214          */
 215         while (bhe != bhb) {
 216                 brelse (*bhe);
 217                 if (++bhe == &buflist[NBUF])
 218                         bhe = buflist;
 219         }
 220         if (!read)
 221                 return -EIO;
 222         filp->f_reada = 1;
 223         if (!IS_RDONLY(inode)) {
 224                 inode->i_atime = CURRENT_TIME;
 225                 inode->i_dirt = 1;
 226         }
 227         return read;
 228 }
 229 
 230 static int ext2_file_write (struct inode * inode, struct file * filp,
     /* [previous][next][first][last][top][bottom][index][help] */
 231                             char * buf, int count)
 232 {
 233         const loff_t two_gb = 2147483647;
 234         loff_t pos;
 235         off_t pos2;
 236         int written, c;
 237         struct buffer_head * bh, *bufferlist[NBUF];
 238         char * p;
 239         struct super_block * sb;
 240         int err;
 241         int i,buffercount,write_error;
 242 
 243         write_error = buffercount = 0;
 244         if (!inode) {
 245                 printk("ext2_file_write: inode = NULL\n");
 246                 return -EINVAL;
 247         }
 248         sb = inode->i_sb;
 249         if (sb->s_flags & MS_RDONLY)
 250                 /*
 251                  * This fs has been automatically remounted ro because of errors
 252                  */
 253                 return -ENOSPC;
 254 
 255         if (!S_ISREG(inode->i_mode)) {
 256                 ext2_warning (sb, "ext2_file_write", "mode = %07o",
 257                               inode->i_mode);
 258                 return -EINVAL;
 259         }
 260         down(&inode->i_sem);
 261         if (filp->f_flags & O_APPEND)
 262                 pos = inode->i_size;
 263         else
 264                 pos = filp->f_pos;
 265         pos2 = (off_t) pos;
 266         /*
 267          * If a file has been opened in synchronous mode, we have to ensure
 268          * that meta-data will also be written synchronously.  Thus, we
 269          * set the i_osync field.  This field is tested by the allocation
 270          * routines.
 271          */
 272         if (filp->f_flags & O_SYNC)
 273                 inode->u.ext2_i.i_osync++;
 274         written = 0;
 275         while (written < count) {
 276                 if (pos > two_gb) {
 277                         if (!written)
 278                                 written = -EFBIG;
 279                         break;
 280                 }
 281                 bh = ext2_getblk (inode, pos2 / sb->s_blocksize, 1, &err);
 282                 if (!bh) {
 283                         if (!written)
 284                                 written = err;
 285                         break;
 286                 }
 287                 c = sb->s_blocksize - (pos2 % sb->s_blocksize);
 288                 if (c > count-written)
 289                         c = count - written;
 290                 if (c != sb->s_blocksize && !bh->b_uptodate) {
 291                         ll_rw_block (READ, 1, &bh);
 292                         wait_on_buffer (bh);
 293                         if (!bh->b_uptodate) {
 294                                 brelse (bh);
 295                                 if (!written)
 296                                         written = -EIO;
 297                                 break;
 298                         }
 299                 }
 300                 p = (pos2 % sb->s_blocksize) + bh->b_data;
 301                 pos2 += c;
 302                 pos += c;
 303                 written += c;
 304                 memcpy_fromfs (p, buf, c);
 305                 buf += c;
 306                 bh->b_uptodate = 1;
 307                 mark_buffer_dirty(bh, 0);
 308                 if (filp->f_flags & O_SYNC)
 309                         bufferlist[buffercount++] = bh;
 310                 else
 311                         brelse(bh);
 312                 if (buffercount == NBUF){
 313                         ll_rw_block(WRITE, buffercount, bufferlist);
 314                         for(i=0; i<buffercount; i++){
 315                                 wait_on_buffer(bufferlist[i]);
 316                                 if (!bufferlist[i]->b_uptodate)
 317                                         write_error=1;
 318                                 brelse(bufferlist[i]);
 319                         }
 320                         buffercount=0;
 321                 }
 322                 if(write_error)
 323                         break;
 324         }
 325         if ( buffercount ){
 326                 ll_rw_block(WRITE, buffercount, bufferlist);
 327                 for(i=0; i<buffercount; i++){
 328                         wait_on_buffer(bufferlist[i]);
 329                         if (!bufferlist[i]->b_uptodate)
 330                                 write_error=1;
 331                         brelse(bufferlist[i]);
 332                 }
 333         }               
 334         if (pos > inode->i_size)
 335                 inode->i_size = pos;
 336         if (filp->f_flags & O_SYNC)
 337                 inode->u.ext2_i.i_osync--;
 338         up(&inode->i_sem);
 339         inode->i_ctime = inode->i_mtime = CURRENT_TIME;
 340         filp->f_pos = pos;
 341         inode->i_dirt = 1;
 342         return written;
 343 }
 344 
 345 /*
 346  * Called when a inode is released. Note that this is different
 347  * from ext2_open: open gets called at every open, but release
 348  * gets called only when /all/ the files are closed.
 349  */
 350 static void ext2_release_file (struct inode * inode, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 351 {
 352         if (filp->f_mode & 2)
 353                 ext2_discard_prealloc (inode);
 354 }

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