root/fs/sysv/file.c

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

DEFINITIONS

This source file includes following definitions.
  1. sysv_file_read
  2. sysv_file_write

   1 /*
   2  *  linux/fs/sysv/file.c
   3  *
   4  *  minix/file.c
   5  *  Copyright (C) 1991, 1992  Linus Torvalds
   6  *
   7  *  coh/file.c
   8  *  Copyright (C) 1993  Pascal Haible, Bruno Haible
   9  *
  10  *  sysv/file.c
  11  *  Copyright (C) 1993  Bruno Haible
  12  *
  13  *  SystemV/Coherent regular file handling primitives
  14  */
  15 
  16 #include <linux/kernel.h>
  17 #include <linux/fs.h>
  18 #include <linux/sysv_fs.h>
  19 #include <linux/errno.h>
  20 #include <linux/fcntl.h>
  21 #include <linux/stat.h>
  22 #include <linux/string.h>
  23 #include <linux/locks.h>
  24 
  25 #include <asm/segment.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/sysv_fs.h>
  34 
  35 static int sysv_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 coh filesystem.
  40  */
  41 static struct file_operations sysv_file_operations = {
  42         NULL,                   /* lseek - default */
  43         sysv_file_read,         /* read */
  44         sysv_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         sysv_sync_file          /* fsync */
  52 };
  53 
  54 struct inode_operations sysv_file_inode_operations = {
  55         &sysv_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         sysv_bmap,              /* bmap */
  70         sysv_truncate,          /* truncate */
  71         NULL                    /* permission */
  72 };
  73 
  74 int sysv_file_read(struct inode * inode, struct file * filp, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
  75 {
  76         struct super_block * sb = inode->i_sb;
  77         int read,left,chars;
  78         unsigned int block;
  79         int blocks, offset;
  80         int bhrequest, uptodate;
  81         struct buffer_head ** bhb, ** bhe;
  82         struct buffer_head * bhreq[NBUF];
  83         struct buffer_head * buflist[NBUF];
  84         unsigned int size;
  85 
  86         if (!inode) {
  87                 printk("sysv_file_read: inode = NULL\n");
  88                 return -EINVAL;
  89         }
  90         if (!S_ISREG(inode->i_mode)) {
  91                 printk("sysv_file_read: mode = %07o\n",inode->i_mode);
  92                 return -EINVAL;
  93         }
  94         offset = filp->f_pos;
  95         size = inode->i_size;
  96         if (offset > size)
  97                 left = 0;
  98         else
  99                 left = size - offset;
 100         if (left > count)
 101                 left = count;
 102         if (left <= 0)
 103                 return 0;
 104         read = 0;
 105         block = offset >> sb->sv_block_size_bits;
 106         offset &= sb->sv_block_size_1;
 107         size = (size + sb->sv_block_size_1) >> sb->sv_block_size_bits;
 108         blocks = (left + offset + sb->sv_block_size_1) >> sb->sv_block_size_bits;
 109         bhb = bhe = buflist;
 110         if (filp->f_reada) {
 111                 blocks += read_ahead[MAJOR(inode->i_dev)] >> (sb->sv_block_size_bits - 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 
 127         do {
 128                 bhrequest = 0;
 129                 uptodate = 1;
 130                 while (blocks) {
 131                         --blocks;
 132                         *bhb = sysv_getblk(inode, block++, 0);
 133                         if (*bhb && !buffer_uptodate(*bhb)) {
 134                                 uptodate = 0;
 135                                 bhreq[bhrequest++] = *bhb;
 136                         }
 137 
 138                         if (++bhb == &buflist[NBUF])
 139                                 bhb = buflist;
 140 
 141                         /* If the block we have on hand is uptodate, go ahead
 142                            and complete processing. */
 143                         if (uptodate)
 144                                 break;
 145                         if (bhb == bhe)
 146                                 break;
 147                 }
 148 
 149                 /* Now request them all */
 150                 if (bhrequest)
 151                         ll_rw_block(READ, bhrequest, bhreq);
 152 
 153                 do { /* Finish off all I/O that has actually completed */
 154                         if (*bhe) {
 155                                 wait_on_buffer(*bhe);
 156                                 if (!buffer_uptodate(*bhe)) {   /* read error? */
 157                                         brelse(*bhe);
 158                                         if (++bhe == &buflist[NBUF])
 159                                                 bhe = buflist;
 160                                         left = 0;
 161                                         break;
 162                                 }
 163                         }
 164                         if (left < sb->sv_block_size - offset)
 165                                 chars = left;
 166                         else
 167                                 chars = sb->sv_block_size - offset;
 168                         filp->f_pos += chars;
 169                         left -= chars;
 170                         read += chars;
 171                         if (*bhe) {
 172                                 memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
 173                                 brelse(*bhe);
 174                                 buf += chars;
 175                         } else {
 176                                 while (chars-- > 0)
 177                                         put_user(0,buf++);
 178                         }
 179                         offset = 0;
 180                         if (++bhe == &buflist[NBUF])
 181                                 bhe = buflist;
 182                 } while (left > 0 && bhe != bhb && (!*bhe || !buffer_locked(*bhe)));
 183         } while (left > 0);
 184 
 185 /* Release the read-ahead blocks */
 186         while (bhe != bhb) {
 187                 brelse(*bhe);
 188                 if (++bhe == &buflist[NBUF])
 189                         bhe = buflist;
 190         };
 191         if (!read)
 192                 return -EIO;
 193         filp->f_reada = 1;
 194         if (!IS_RDONLY(inode)) {
 195                 inode->i_atime = CURRENT_TIME;
 196                 inode->i_dirt = 1;
 197         }
 198         return read;
 199 }
 200 
 201 static int sysv_file_write(struct inode * inode, struct file * filp, const char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 202 {
 203         struct super_block * sb = inode->i_sb;
 204         off_t pos;
 205         int written,c;
 206         struct buffer_head * bh;
 207         char * p;
 208 
 209         if (!inode) {
 210                 printk("sysv_file_write: inode = NULL\n");
 211                 return -EINVAL;
 212         }
 213         if (!S_ISREG(inode->i_mode)) {
 214                 printk("sysv_file_write: mode = %07o\n",inode->i_mode);
 215                 return -EINVAL;
 216         }
 217 /*
 218  * ok, append may not work when many processes are writing at the same time
 219  * but so what. That way leads to madness anyway.
 220  * But we need to protect against simultaneous truncate as we may end up
 221  * writing our data into blocks that have meanwhile been incorporated into
 222  * the freelist, thereby trashing the freelist.
 223  */
 224         if (filp->f_flags & O_APPEND)
 225                 pos = inode->i_size;
 226         else
 227                 pos = filp->f_pos;
 228         written = 0;
 229         while (written<count) {
 230                 bh = sysv_getblk (inode, pos >> sb->sv_block_size_bits, 1);
 231                 if (!bh) {
 232                         if (!written)
 233                                 written = -ENOSPC;
 234                         break;
 235                 }
 236                 c = sb->sv_block_size - (pos & sb->sv_block_size_1);
 237                 if (c > count-written)
 238                         c = count-written;
 239                 if (c != sb->sv_block_size && !buffer_uptodate(bh)) {
 240                         ll_rw_block(READ, 1, &bh);
 241                         wait_on_buffer(bh);
 242                         if (!buffer_uptodate(bh)) {
 243                                 brelse(bh);
 244                                 if (!written)
 245                                         written = -EIO;
 246                                 break;
 247                         }
 248                 }
 249                 /* now either c==sb->sv_block_size or buffer_uptodate(bh) */
 250                 p = (pos & sb->sv_block_size_1) + bh->b_data;
 251                 pos += c;
 252                 if (pos > inode->i_size) {
 253                         inode->i_size = pos;
 254                         inode->i_dirt = 1;
 255                 }
 256                 written += c;
 257                 memcpy_fromfs(p,buf,c);
 258                 buf += c;
 259                 mark_buffer_uptodate(bh, 1);
 260                 mark_buffer_dirty(bh, 0);
 261                 brelse(bh);
 262         }
 263         inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 264         filp->f_pos = pos;
 265         inode->i_dirt = 1;
 266         return written;
 267 }

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