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

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