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

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