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    16
  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 *, 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         ext_bmap,               /* bmap */
  68         ext_truncate,           /* truncate */
  69         NULL                    /* permission */
  70 };
  71 
  72 static int ext_file_read(struct inode * inode, struct file * filp, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
  73 {
  74         int read,left,chars;
  75         int block, blocks, offset;
  76         int bhrequest, uptodate;
  77         struct buffer_head ** bhb, ** bhe;
  78         struct buffer_head * bhreq[NBUF];
  79         struct buffer_head * buflist[NBUF];
  80         unsigned int size;
  81 
  82         if (!inode) {
  83                 printk("ext_file_read: inode = NULL\n");
  84                 return -EINVAL;
  85         }
  86         if (!S_ISREG(inode->i_mode)) {
  87                 printk("ext_file_read: mode = %07o\n",inode->i_mode);
  88                 return -EINVAL;
  89         }
  90         offset = filp->f_pos;
  91         size = inode->i_size;
  92         if (offset > size)
  93                 left = 0;
  94         else
  95                 left = size - offset;
  96         if (left > count)
  97                 left = count;
  98         if (left <= 0)
  99                 return 0;
 100         read = 0;
 101         block = offset >> BLOCK_SIZE_BITS;
 102         offset &= BLOCK_SIZE-1;
 103         size = (size + (BLOCK_SIZE-1)) >> BLOCK_SIZE_BITS;
 104         blocks = (left + offset + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS;
 105         bhb = bhe = buflist;
 106         if (filp->f_reada) {
 107                 blocks += read_ahead[MAJOR(inode->i_dev)] / (BLOCK_SIZE >> 9);
 108                 if (block + blocks > size)
 109                         blocks = size - block;
 110         }
 111 
 112         /* We do this in a two stage process.  We first try and request
 113            as many blocks as we can, then we wait for the first one to
 114            complete, and then we try and wrap up as many as are actually
 115            done.  This routine is rather generic, in that it can be used
 116            in a filesystem by substituting the appropriate function in
 117            for getblk.
 118 
 119            This routine is optimized to make maximum use of the various
 120            buffers and caches. */
 121 
 122         do {
 123                 bhrequest = 0;
 124                 uptodate = 1;
 125                 while (blocks) {
 126                         --blocks;
 127                         *bhb = ext_getblk(inode, block++, 0);
 128                         if (*bhb && !(*bhb)->b_uptodate) {
 129                                 uptodate = 0;
 130                                 bhreq[bhrequest++] = *bhb;
 131                         }
 132 
 133                         if (++bhb == &buflist[NBUF])
 134                                 bhb = buflist;
 135 
 136                         /* If the block we have on hand is uptodate, go ahead
 137                            and complete processing. */
 138                         if (uptodate)
 139                                 break;
 140                         if (bhb == bhe)
 141                                 break;
 142                 }
 143 
 144                 /* Now request them all */
 145                 if (bhrequest)
 146                         ll_rw_block(READ, bhrequest, bhreq);
 147 
 148                 do { /* Finish off all I/O that has actually completed */
 149                         if (*bhe) {
 150                                 wait_on_buffer(*bhe);
 151                                 if (!(*bhe)->b_uptodate) {      /* read error? */
 152                                         left = 0;
 153                                         break;
 154                                 }
 155                         }
 156                         if (left < BLOCK_SIZE - offset)
 157                                 chars = left;
 158                         else
 159                                 chars = BLOCK_SIZE - offset;
 160                         filp->f_pos += chars;
 161                         left -= chars;
 162                         read += chars;
 163                         if (*bhe) {
 164                                 memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
 165                                 brelse(*bhe);
 166                                 buf += chars;
 167                         } else {
 168                                 while (chars-->0)
 169                                         put_fs_byte(0,buf++);
 170                         }
 171                         offset = 0;
 172                         if (++bhe == &buflist[NBUF])
 173                                 bhe = buflist;
 174                 } while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock));
 175         } while (left > 0);
 176 
 177 /* Release the read-ahead blocks */
 178         while (bhe != bhb) {
 179                 brelse(*bhe);
 180                 if (++bhe == &buflist[NBUF])
 181                         bhe = buflist;
 182         };
 183         if (!read)
 184                 return -EIO;
 185         filp->f_reada = 1;
 186         if (!IS_RDONLY(inode)) {
 187                 inode->i_atime = CURRENT_TIME;
 188                 inode->i_dirt = 1;
 189         }
 190         return read;
 191 }
 192 
 193 static int ext_file_write(struct inode * inode, struct file * filp, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 194 {
 195         off_t pos;
 196         int written,c;
 197         struct buffer_head * bh;
 198         char * p;
 199 
 200         if (!inode) {
 201                 printk("ext_file_write: inode = NULL\n");
 202                 return -EINVAL;
 203         }
 204         if (!S_ISREG(inode->i_mode)) {
 205                 printk("ext_file_write: mode = %07o\n",inode->i_mode);
 206                 return -EINVAL;
 207         }
 208 /*
 209  * ok, append may not work when many processes are writing at the same time
 210  * but so what. That way leads to madness anyway.
 211  */
 212         if (filp->f_flags & O_APPEND)
 213                 pos = inode->i_size;
 214         else
 215                 pos = filp->f_pos;
 216         written = 0;
 217         while (written<count) {
 218                 bh = ext_getblk(inode,pos/BLOCK_SIZE,1);
 219                 if (!bh) {
 220                         if (!written)
 221                                 written = -ENOSPC;
 222                         break;
 223                 }
 224                 c = BLOCK_SIZE - (pos % BLOCK_SIZE);
 225                 if (c > count-written)
 226                         c = count-written;
 227                 if (c != BLOCK_SIZE && !bh->b_uptodate) {
 228                         ll_rw_block(READ, 1, &bh);
 229                         wait_on_buffer(bh);
 230                         if (!bh->b_uptodate) {
 231                                 brelse(bh);
 232                                 if (!written)
 233                                         written = -EIO;
 234                                 break;
 235                         }
 236                 }
 237                 p = (pos % BLOCK_SIZE) + bh->b_data;
 238                 pos += c;
 239                 if (pos > inode->i_size) {
 240                         inode->i_size = pos;
 241                         inode->i_dirt = 1;
 242                 }
 243                 written += c;
 244                 memcpy_fromfs(p,buf,c);
 245                 buf += c;
 246                 bh->b_uptodate = 1;
 247                 bh->b_dirt = 1;
 248                 brelse(bh);
 249         }
 250         inode->i_mtime = CURRENT_TIME;
 251         inode->i_ctime = CURRENT_TIME;
 252         filp->f_pos = pos;
 253         inode->i_dirt = 1;
 254         return written;
 255 }

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