root/fs/ext/file.c

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

DEFINITIONS

This source file includes following definitions.
  1. ext_file_read
  2. ext_file_write

   1 /*
   2  *  linux/fs/ext/file.c
   3  *
   4  *  Copyright (C) 1992 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  *  ext 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/ext_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    32
  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/ext_fs.h>
  33 
  34 static int ext_file_read(struct inode *, struct file *, char *, int);
  35 static int ext_file_write(struct inode *, struct file *, const char *, int);
  36 
  37 /*
  38  * We have mostly NULL's here: the current defaults are ok for
  39  * the ext filesystem.
  40  */
  41 static struct file_operations ext_file_operations = {
  42         NULL,                   /* lseek - default */
  43         ext_file_read,  /* read */
  44         ext_file_write, /* write */
  45         NULL,                   /* readdir - bad */
  46         NULL,                   /* select - default */
  47         NULL,                   /* ioctl - default */
  48         generic_mmap,           /* mmap */
  49         NULL,                   /* no special open is needed */
  50         NULL,                   /* release */
  51         ext_sync_file                   /* fsync */
  52 };
  53 
  54 struct inode_operations ext_file_inode_operations = {
  55         &ext_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         generic_readpage,       /* readpage */
  68         NULL,                   /* writepage */
  69         ext_bmap,               /* bmap */
  70         ext_truncate,           /* truncate */
  71         NULL                    /* permission */
  72 };
  73 
  74 static int ext_file_read(struct inode * inode, struct file * filp, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
  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         unsigned int size;
  83 
  84         if (!inode) {
  85                 printk("ext_file_read: inode = NULL\n");
  86                 return -EINVAL;
  87         }
  88         if (!S_ISREG(inode->i_mode)) {
  89                 printk("ext_file_read: mode = %07o\n",inode->i_mode);
  90                 return -EINVAL;
  91         }
  92         offset = filp->f_pos;
  93         size = inode->i_size;
  94         if (offset > size)
  95                 left = 0;
  96         else
  97                 left = size - offset;
  98         if (left > count)
  99                 left = count;
 100         if (left <= 0)
 101                 return 0;
 102         read = 0;
 103         block = offset >> BLOCK_SIZE_BITS;
 104         offset &= BLOCK_SIZE-1;
 105         size = (size + (BLOCK_SIZE-1)) >> BLOCK_SIZE_BITS;
 106         blocks = (left + offset + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS;
 107         bhb = bhe = buflist;
 108         if (filp->f_reada) {
 109                 if(blocks < read_ahead[MAJOR(inode->i_dev)] / (BLOCK_SIZE >> 9))
 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 = ext_getblk(inode, block++, 0);
 131                         if (*bhb && !buffer_uptodate(*bhb)) {
 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                         if (bhb == bhe)
 144                                 break;
 145                 }
 146 
 147                 /* Now request them all */
 148                 if (bhrequest)
 149                         ll_rw_block(READ, bhrequest, bhreq);
 150 
 151                 do { /* Finish off all I/O that has actually completed */
 152                         if (*bhe) {
 153                                 wait_on_buffer(*bhe);
 154                                 if (!buffer_uptodate(*bhe)) {   /* read error? */
 155                                         brelse(*bhe);
 156                                         if (++bhe == &buflist[NBUF])
 157                                           bhe = buflist;
 158                                         left = 0;
 159                                         break;
 160                                 }
 161                         }
 162                         if (left < BLOCK_SIZE - offset)
 163                                 chars = left;
 164                         else
 165                                 chars = BLOCK_SIZE - offset;
 166                         filp->f_pos += chars;
 167                         left -= chars;
 168                         read += chars;
 169                         if (*bhe) {
 170                                 memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
 171                                 brelse(*bhe);
 172                                 buf += chars;
 173                         } else {
 174                                 while (chars-->0)
 175                                         put_user(0,buf++);
 176                         }
 177                         offset = 0;
 178                         if (++bhe == &buflist[NBUF])
 179                                 bhe = buflist;
 180                 } while (left > 0 && bhe != bhb && (!*bhe || !buffer_locked(*bhe)));
 181         } while (left > 0);
 182 
 183 /* Release the read-ahead blocks */
 184         while (bhe != bhb) {
 185                 brelse(*bhe);
 186                 if (++bhe == &buflist[NBUF])
 187                         bhe = buflist;
 188         };
 189         if (!read)
 190                 return -EIO;
 191         filp->f_reada = 1;
 192         if (!IS_RDONLY(inode)) {
 193                 inode->i_atime = CURRENT_TIME;
 194                 inode->i_dirt = 1;
 195         }
 196         return read;
 197 }
 198 
 199 static int ext_file_write(struct inode * inode, struct file * filp, const char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 200 {
 201         off_t pos;
 202         int written,c;
 203         struct buffer_head * bh;
 204         char * p;
 205 
 206         if (!inode) {
 207                 printk("ext_file_write: inode = NULL\n");
 208                 return -EINVAL;
 209         }
 210         if (!S_ISREG(inode->i_mode)) {
 211                 printk("ext_file_write: mode = %07o\n",inode->i_mode);
 212                 return -EINVAL;
 213         }
 214 /*
 215  * ok, append may not work when many processes are writing at the same time
 216  * but so what. That way leads to madness anyway.
 217  */
 218         if (filp->f_flags & O_APPEND)
 219                 pos = inode->i_size;
 220         else
 221                 pos = filp->f_pos;
 222         written = 0;
 223         while (written<count) {
 224                 bh = ext_getblk(inode,pos/BLOCK_SIZE,1);
 225                 if (!bh) {
 226                         if (!written)
 227                                 written = -ENOSPC;
 228                         break;
 229                 }
 230                 c = BLOCK_SIZE - (pos % BLOCK_SIZE);
 231                 if (c > count-written)
 232                         c = count-written;
 233                 if (c != BLOCK_SIZE && !buffer_uptodate(bh)) {
 234                         ll_rw_block(READ, 1, &bh);
 235                         wait_on_buffer(bh);
 236                         if (!buffer_uptodate(bh)) {
 237                                 brelse(bh);
 238                                 if (!written)
 239                                         written = -EIO;
 240                                 break;
 241                         }
 242                 }
 243                 p = (pos % BLOCK_SIZE) + bh->b_data;
 244                 pos += c;
 245                 if (pos > inode->i_size) {
 246                         inode->i_size = pos;
 247                         inode->i_dirt = 1;
 248                 }
 249                 written += c;
 250                 memcpy_fromfs(p,buf,c);
 251                 buf += c;
 252                 mark_buffer_uptodate(bh, 1);
 253                 mark_buffer_dirty(bh, 0);
 254                 brelse(bh);
 255         }
 256         inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 257         filp->f_pos = pos;
 258         inode->i_dirt = 1;
 259         return written;
 260 }

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