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 #include <linux/pagemap.h>
  26 
  27 #define NBUF    32
  28 
  29 #define MIN(a,b) (((a)<(b))?(a):(b))
  30 #define MAX(a,b) (((a)>(b))?(a):(b))
  31 
  32 #include <linux/fs.h>
  33 #include <linux/ext_fs.h>
  34 
  35 static int ext_file_read(struct inode *, struct file *, char *, int);
  36 static int ext_file_write(struct inode *, struct file *, const char *, int);
  37 
  38 /*
  39  * We have mostly NULL's here: the current defaults are ok for
  40  * the ext filesystem.
  41  */
  42 static struct file_operations ext_file_operations = {
  43         NULL,                   /* lseek - default */
  44         ext_file_read,  /* read */
  45         ext_file_write, /* write */
  46         NULL,                   /* readdir - bad */
  47         NULL,                   /* select - default */
  48         NULL,                   /* ioctl - default */
  49         generic_file_mmap,      /* mmap */
  50         NULL,                   /* no special open is needed */
  51         NULL,                   /* release */
  52         ext_sync_file                   /* fsync */
  53 };
  54 
  55 struct inode_operations ext_file_inode_operations = {
  56         &ext_file_operations,   /* default file operations */
  57         NULL,                   /* create */
  58         NULL,                   /* lookup */
  59         NULL,                   /* link */
  60         NULL,                   /* unlink */
  61         NULL,                   /* symlink */
  62         NULL,                   /* mkdir */
  63         NULL,                   /* rmdir */
  64         NULL,                   /* mknod */
  65         NULL,                   /* rename */
  66         NULL,                   /* readlink */
  67         NULL,                   /* follow_link */
  68         generic_readpage,       /* readpage */
  69         NULL,                   /* writepage */
  70         ext_bmap,               /* bmap */
  71         ext_truncate,           /* truncate */
  72         NULL                    /* permission */
  73 };
  74 
  75 static int ext_file_read(struct inode * inode, struct file * filp, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
  76 {
  77         int read,left,chars;
  78         int block, blocks, offset;
  79         int bhrequest, uptodate;
  80         struct buffer_head ** bhb, ** bhe;
  81         struct buffer_head * bhreq[NBUF];
  82         struct buffer_head * buflist[NBUF];
  83         unsigned int size;
  84 
  85         if (!inode) {
  86                 printk("ext_file_read: inode = NULL\n");
  87                 return -EINVAL;
  88         }
  89         if (!S_ISREG(inode->i_mode)) {
  90                 printk("ext_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 >> BLOCK_SIZE_BITS;
 105         offset &= BLOCK_SIZE-1;
 106         size = (size + (BLOCK_SIZE-1)) >> BLOCK_SIZE_BITS;
 107         blocks = (left + offset + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS;
 108         bhb = bhe = buflist;
 109         if (filp->f_reada) {
 110                 if(blocks < read_ahead[MAJOR(inode->i_dev)] / (BLOCK_SIZE >> 9))
 111                   blocks = read_ahead[MAJOR(inode->i_dev)] / (BLOCK_SIZE >> 9);
 112                 if (block + blocks > size)
 113                         blocks = size - block;
 114         }
 115 
 116         /* We do this in a two stage process.  We first try and request
 117            as many blocks as we can, then we wait for the first one to
 118            complete, and then we try and wrap up as many as are actually
 119            done.  This routine is rather generic, in that it can be used
 120            in a filesystem by substituting the appropriate function in
 121            for getblk.
 122 
 123            This routine is optimized to make maximum use of the various
 124            buffers and caches. */
 125 
 126         do {
 127                 bhrequest = 0;
 128                 uptodate = 1;
 129                 while (blocks) {
 130                         --blocks;
 131                         *bhb = ext_getblk(inode, block++, 0);
 132                         if (*bhb && !buffer_uptodate(*bhb)) {
 133                                 uptodate = 0;
 134                                 bhreq[bhrequest++] = *bhb;
 135                         }
 136 
 137                         if (++bhb == &buflist[NBUF])
 138                                 bhb = buflist;
 139 
 140                         /* If the block we have on hand is uptodate, go ahead
 141                            and complete processing. */
 142                         if (uptodate)
 143                                 break;
 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 (!buffer_uptodate(*bhe)) {   /* read error? */
 156                                         brelse(*bhe);
 157                                         if (++bhe == &buflist[NBUF])
 158                                           bhe = buflist;
 159                                         left = 0;
 160                                         break;
 161                                 }
 162                         }
 163                         if (left < BLOCK_SIZE - offset)
 164                                 chars = left;
 165                         else
 166                                 chars = BLOCK_SIZE - offset;
 167                         filp->f_pos += chars;
 168                         left -= chars;
 169                         read += chars;
 170                         if (*bhe) {
 171                                 memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
 172                                 brelse(*bhe);
 173                                 buf += chars;
 174                         } else {
 175                                 while (chars-->0)
 176                                         put_user(0,buf++);
 177                         }
 178                         offset = 0;
 179                         if (++bhe == &buflist[NBUF])
 180                                 bhe = buflist;
 181                 } while (left > 0 && bhe != bhb && (!*bhe || !buffer_locked(*bhe)));
 182         } while (left > 0);
 183 
 184 /* Release the read-ahead blocks */
 185         while (bhe != bhb) {
 186                 brelse(*bhe);
 187                 if (++bhe == &buflist[NBUF])
 188                         bhe = buflist;
 189         };
 190         if (!read)
 191                 return -EIO;
 192         filp->f_reada = 1;
 193         if (!IS_RDONLY(inode)) {
 194                 inode->i_atime = CURRENT_TIME;
 195                 inode->i_dirt = 1;
 196         }
 197         return read;
 198 }
 199 
 200 static int ext_file_write(struct inode * inode, struct file * filp, const char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 201 {
 202         off_t pos;
 203         int written,c;
 204         struct buffer_head * bh;
 205         char * p;
 206 
 207         if (!inode) {
 208                 printk("ext_file_write: inode = NULL\n");
 209                 return -EINVAL;
 210         }
 211         if (!S_ISREG(inode->i_mode)) {
 212                 printk("ext_file_write: mode = %07o\n",inode->i_mode);
 213                 return -EINVAL;
 214         }
 215 /*
 216  * ok, append may not work when many processes are writing at the same time
 217  * but so what. That way leads to madness anyway.
 218  */
 219         if (filp->f_flags & O_APPEND)
 220                 pos = inode->i_size;
 221         else
 222                 pos = filp->f_pos;
 223         written = 0;
 224         while (written<count) {
 225                 bh = ext_getblk(inode,pos/BLOCK_SIZE,1);
 226                 if (!bh) {
 227                         if (!written)
 228                                 written = -ENOSPC;
 229                         break;
 230                 }
 231                 c = BLOCK_SIZE - (pos % BLOCK_SIZE);
 232                 if (c > count-written)
 233                         c = count-written;
 234                 if (c != BLOCK_SIZE && !buffer_uptodate(bh)) {
 235                         ll_rw_block(READ, 1, &bh);
 236                         wait_on_buffer(bh);
 237                         if (!buffer_uptodate(bh)) {
 238                                 brelse(bh);
 239                                 if (!written)
 240                                         written = -EIO;
 241                                 break;
 242                         }
 243                 }
 244                 p = (pos % BLOCK_SIZE) + bh->b_data;
 245                 memcpy_fromfs(p,buf,c);
 246                 update_vm_cache(inode, pos, p, c);
 247                 pos += c;
 248                 if (pos > inode->i_size) {
 249                         inode->i_size = pos;
 250                         inode->i_dirt = 1;
 251                 }
 252                 written += c;
 253                 buf += c;
 254                 mark_buffer_uptodate(bh, 1);
 255                 mark_buffer_dirty(bh, 0);
 256                 brelse(bh);
 257         }
 258         inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 259         filp->f_pos = pos;
 260         inode->i_dirt = 1;
 261         return written;
 262 }

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