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 };
  56 
  57 struct inode_operations ext2_file_inode_operations = {
  58         &ext2_file_operations,/* default file operations */
  59         NULL,                   /* create */
  60         NULL,                   /* lookup */
  61         NULL,                   /* link */
  62         NULL,                   /* unlink */
  63         NULL,                   /* symlink */
  64         NULL,                   /* mkdir */
  65         NULL,                   /* rmdir */
  66         NULL,                   /* mknod */
  67         NULL,                   /* rename */
  68         NULL,                   /* readlink */
  69         NULL,                   /* follow_link */
  70         ext2_bmap,              /* bmap */
  71         ext2_truncate,          /* truncate */
  72         ext2_permission         /* permission */
  73 };
  74 
  75 static int ext2_file_read (struct inode * inode, struct file * filp,
     /* [previous][next][first][last][top][bottom][index][help] */
  76                     char * buf, int count)
  77 {
  78         int read, left, chars;
  79         int block, blocks, offset;
  80         int bhrequest, uptodate;
  81         int clusterblocks;
  82         struct buffer_head ** bhb, ** bhe;
  83         struct buffer_head * bhreq[NBUF];
  84         struct buffer_head * buflist[NBUF];
  85         struct super_block * sb;
  86         unsigned int size;
  87         int err;
  88 
  89         if (!inode) {
  90                 printk ("ext2_file_read: inode = NULL\n");
  91                 return -EINVAL;
  92         }
  93         sb = inode->i_sb;
  94         if (!S_ISREG(inode->i_mode)) {
  95                 ext2_warning (sb, "ext2_file_read", "mode = %07o",
  96                               inode->i_mode);
  97                 return -EINVAL;
  98         }
  99         offset = filp->f_pos;
 100         size = inode->i_size;
 101         if (offset > size)
 102                 left = 0;
 103         else
 104                 left = size - offset;
 105         if (left > count)
 106                 left = count;
 107         if (left <= 0)
 108                 return 0;
 109         read = 0;
 110         block = offset >> EXT2_BLOCK_SIZE_BITS(sb);
 111         offset &= (sb->s_blocksize - 1);
 112         size = (size + sb->s_blocksize - 1) >> EXT2_BLOCK_SIZE_BITS(sb);
 113         blocks = (left + offset + sb->s_blocksize - 1) >> EXT2_BLOCK_SIZE_BITS(sb);
 114         bhb = bhe = buflist;
 115         if (filp->f_reada) {
 116                 if (blocks < read_ahead[MAJOR(inode->i_dev)] >> (EXT2_BLOCK_SIZE_BITS(sb) - 9))
 117                     blocks = read_ahead[MAJOR(inode->i_dev)] >> (EXT2_BLOCK_SIZE_BITS(sb) - 9);
 118                 if (block + blocks > size)
 119                         blocks = size - block;
 120         }
 121 
 122         /*
 123          * We do this in a two stage process.  We first try and request
 124          * as many blocks as we can, then we wait for the first one to
 125          * complete, and then we try and wrap up as many as are actually
 126          * done.  This routine is rather generic, in that it can be used
 127          * in a filesystem by substituting the appropriate function in
 128          * for getblk
 129          *
 130          * This routine is optimized to make maximum use of the various
 131          * buffers and caches.
 132          */
 133 
 134         clusterblocks = 0;
 135 
 136         do {
 137                 bhrequest = 0;
 138                 uptodate = 1;
 139                 while (blocks) {
 140                         --blocks;
 141 #if 1
 142                         if(!clusterblocks) clusterblocks = ext2_getcluster(inode, block);
 143                         if(clusterblocks) clusterblocks--;
 144 #endif
 145 
 146                         *bhb = ext2_getblk (inode, block++, 0, &err);
 147                         if (*bhb && !(*bhb)->b_uptodate) {
 148                                 uptodate = 0;
 149                                 bhreq[bhrequest++] = *bhb;
 150                         }
 151 
 152                         if (++bhb == &buflist[NBUF])
 153                                 bhb = buflist;
 154 
 155                         /*
 156                          * If the block we have on hand is uptodate, go ahead
 157                          * and complete processing
 158                          */
 159                         if (uptodate)
 160                                 break;
 161 
 162                         if (bhb == bhe)
 163                                 break;
 164                 }
 165 
 166                 /*
 167                  * Now request them all
 168                  */
 169                 if (bhrequest)
 170                         ll_rw_block (READ, bhrequest, bhreq);
 171 
 172                 do {
 173                         /*
 174                          * Finish off all I/O that has actually completed
 175                          */
 176                         if (*bhe) {
 177                                 wait_on_buffer (*bhe);
 178                                 if (!(*bhe)->b_uptodate) { /* read error? */
 179                                         brelse(*bhe);
 180                                         if (++bhe == &buflist[NBUF])
 181                                           bhe = buflist;
 182                                         left = 0;
 183                                         break;
 184                                 }
 185                         }
 186                         if (left < sb->s_blocksize - offset)
 187                                 chars = left;
 188                         else
 189                                 chars = sb->s_blocksize - offset;
 190                         filp->f_pos += chars;
 191                         left -= chars;
 192                         read += chars;
 193                         if (*bhe) {
 194                                 memcpy_tofs (buf, offset + (*bhe)->b_data,
 195                                              chars);
 196                                 brelse (*bhe);
 197                                 buf += chars;
 198                         } else {
 199                                 while (chars-- > 0)
 200                                         put_fs_byte (0, buf++);
 201                         }
 202                         offset = 0;
 203                         if (++bhe == &buflist[NBUF])
 204                                 bhe = buflist;
 205                 } while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock));
 206         } while (left > 0);
 207 
 208         /*
 209          * Release the read-ahead blocks
 210          */
 211         while (bhe != bhb) {
 212                 brelse (*bhe);
 213                 if (++bhe == &buflist[NBUF])
 214                         bhe = buflist;
 215         }
 216         if (!read)
 217                 return -EIO;
 218         filp->f_reada = 1;
 219         if (!IS_RDONLY(inode)) {
 220                 inode->i_atime = CURRENT_TIME;
 221                 inode->i_dirt = 1;
 222         }
 223         return read;
 224 }
 225 
 226 static int ext2_file_write (struct inode * inode, struct file * filp,
     /* [previous][next][first][last][top][bottom][index][help] */
 227                             char * buf, int count)
 228 {
 229         off_t pos;
 230         int written, c;
 231         struct buffer_head * bh;
 232         char * p;
 233         struct super_block * sb;
 234         int err;
 235 
 236         if (!inode) {
 237                 printk("ext2_file_write: inode = NULL\n");
 238                 return -EINVAL;
 239         }
 240         sb = inode->i_sb;
 241         if (sb->s_flags & MS_RDONLY)
 242                 /*
 243                  * This fs has been automatically remounted ro because of errors
 244                  */
 245                 return -ENOSPC;
 246 
 247         if (!S_ISREG(inode->i_mode)) {
 248                 ext2_warning (sb, "ext2_file_write", "mode = %07o\n",
 249                               inode->i_mode);
 250                 return -EINVAL;
 251         }
 252         down(&inode->i_sem);
 253         if (filp->f_flags & O_APPEND)
 254                 pos = inode->i_size;
 255         else
 256                 pos = filp->f_pos;
 257         written = 0;
 258         while (written < count) {
 259                 bh = ext2_getblk (inode, pos / sb->s_blocksize, 1, &err);
 260                 if (!bh) {
 261                         if (!written)
 262                                 written = err;
 263                         break;
 264                 }
 265                 c = sb->s_blocksize - (pos % sb->s_blocksize);
 266                 if (c > count-written)
 267                         c = count - written;
 268                 if (c != sb->s_blocksize && !bh->b_uptodate) {
 269                         ll_rw_block (READ, 1, &bh);
 270                         wait_on_buffer (bh);
 271                         if (!bh->b_uptodate) {
 272                                 brelse (bh);
 273                                 if (!written)
 274                                         written = -EIO;
 275                                 break;
 276                         }
 277                 }
 278                 p = (pos % sb->s_blocksize) + bh->b_data;
 279                 pos += c;
 280                 if (pos > inode->i_size) {
 281                         inode->i_size = pos;
 282                         inode->i_dirt = 1;
 283                 }
 284                 written += c;
 285                 memcpy_fromfs (p, buf, c);
 286                 buf += c;
 287                 bh->b_uptodate = 1;
 288                 mark_buffer_dirty(bh, 0);
 289                 brelse (bh);
 290         }
 291         up(&inode->i_sem);
 292         inode->i_ctime = inode->i_mtime = CURRENT_TIME;
 293         filp->f_pos = pos;
 294         inode->i_dirt = 1;
 295         return written;
 296 }
 297 
 298 /*
 299  * Called when a inode is released. Note that this is different
 300  * from ext2_open: open gets called at every open, but release
 301  * gets called only when /all/ the files are closed.
 302  */
 303 static void ext2_release_file (struct inode * inode, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 304 {
 305         if (filp->f_mode & 2)
 306                 ext2_discard_prealloc (inode);
 307 }

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