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 #ifdef MODULE
  17 #include <linux/module.h>
  18 #endif
  19 
  20 #include <asm/segment.h>
  21 
  22 #include <linux/kernel.h>
  23 #include <linux/fs.h>
  24 #include <linux/sysv_fs.h>
  25 #include <linux/errno.h>
  26 #include <linux/fcntl.h>
  27 #include <linux/stat.h>
  28 #include <linux/string.h>
  29 #include <linux/locks.h>
  30 
  31 #define NBUF    32
  32 
  33 #define MIN(a,b) (((a)<(b))?(a):(b))
  34 #define MAX(a,b) (((a)>(b))?(a):(b))
  35 
  36 #include <linux/fs.h>
  37 #include <linux/sysv_fs.h>
  38 
  39 static int sysv_file_write(struct inode *, struct file *, const char *, int);
  40 
  41 /*
  42  * We have mostly NULL's here: the current defaults are ok for
  43  * the coh filesystem.
  44  */
  45 static struct file_operations sysv_file_operations = {
  46         NULL,                   /* lseek - default */
  47         sysv_file_read,         /* read */
  48         sysv_file_write,        /* write */
  49         NULL,                   /* readdir - bad */
  50         NULL,                   /* select - default */
  51         NULL,                   /* ioctl - default */
  52         generic_mmap,           /* mmap */
  53         NULL,                   /* no special open is needed */
  54         NULL,                   /* release */
  55         sysv_sync_file          /* fsync */
  56 };
  57 
  58 struct inode_operations sysv_file_inode_operations = {
  59         &sysv_file_operations,  /* default file operations */
  60         NULL,                   /* create */
  61         NULL,                   /* lookup */
  62         NULL,                   /* link */
  63         NULL,                   /* unlink */
  64         NULL,                   /* symlink */
  65         NULL,                   /* mkdir */
  66         NULL,                   /* rmdir */
  67         NULL,                   /* mknod */
  68         NULL,                   /* rename */
  69         NULL,                   /* readlink */
  70         NULL,                   /* follow_link */
  71         sysv_bmap,              /* bmap */
  72         sysv_truncate,          /* truncate */
  73         NULL                    /* permission */
  74 };
  75 
  76 int sysv_file_read(struct inode * inode, struct file * filp, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
  77 {
  78         struct super_block * sb = inode->i_sb;
  79         int read,left,chars;
  80         unsigned int block;
  81         int blocks, offset;
  82         int bhrequest, uptodate;
  83         struct buffer_head ** bhb, ** bhe;
  84         struct buffer_head * bhreq[NBUF];
  85         struct buffer_head * buflist[NBUF];
  86         unsigned int size;
  87 
  88         if (!inode) {
  89                 printk("sysv_file_read: inode = NULL\n");
  90                 return -EINVAL;
  91         }
  92         if (!S_ISREG(inode->i_mode)) {
  93                 printk("sysv_file_read: mode = %07o\n",inode->i_mode);
  94                 return -EINVAL;
  95         }
  96         offset = filp->f_pos;
  97         size = inode->i_size;
  98         if (offset > size)
  99                 left = 0;
 100         else
 101                 left = size - offset;
 102         if (left > count)
 103                 left = count;
 104         if (left <= 0)
 105                 return 0;
 106         read = 0;
 107         block = offset >> sb->sv_block_size_bits;
 108         offset &= sb->sv_block_size_1;
 109         size = (size + sb->sv_block_size_1) >> sb->sv_block_size_bits;
 110         blocks = (left + offset + sb->sv_block_size_1) >> sb->sv_block_size_bits;
 111         bhb = bhe = buflist;
 112         if (filp->f_reada) {
 113                 blocks += read_ahead[MAJOR(inode->i_dev)] >> (sb->sv_block_size_bits - 9);
 114                 if (block + blocks > size)
 115                         blocks = size - block;
 116         }
 117 
 118         /* We do this in a two stage process.  We first try and request
 119            as many blocks as we can, then we wait for the first one to
 120            complete, and then we try and wrap up as many as are actually
 121            done.  This routine is rather generic, in that it can be used
 122            in a filesystem by substituting the appropriate function in
 123            for getblk.
 124 
 125            This routine is optimized to make maximum use of the various
 126            buffers and caches.
 127          */
 128 
 129         do {
 130                 bhrequest = 0;
 131                 uptodate = 1;
 132                 while (blocks) {
 133                         --blocks;
 134                         *bhb = sysv_getblk(inode, block++, 0);
 135                         if (*bhb && !(*bhb)->b_uptodate) {
 136                                 uptodate = 0;
 137                                 bhreq[bhrequest++] = *bhb;
 138                         }
 139 
 140                         if (++bhb == &buflist[NBUF])
 141                                 bhb = buflist;
 142 
 143                         /* If the block we have on hand is uptodate, go ahead
 144                            and complete processing. */
 145                         if (uptodate)
 146                                 break;
 147                         if (bhb == bhe)
 148                                 break;
 149                 }
 150 
 151                 /* Now request them all */
 152                 if (bhrequest)
 153                         ll_rw_block(READ, bhrequest, bhreq);
 154 
 155                 do { /* Finish off all I/O that has actually completed */
 156                         if (*bhe) {
 157                                 wait_on_buffer(*bhe);
 158                                 if (!(*bhe)->b_uptodate) {      /* read error? */
 159                                         brelse(*bhe);
 160                                         if (++bhe == &buflist[NBUF])
 161                                                 bhe = buflist;
 162                                         left = 0;
 163                                         break;
 164                                 }
 165                         }
 166                         if (left < sb->sv_block_size - offset)
 167                                 chars = left;
 168                         else
 169                                 chars = sb->sv_block_size - offset;
 170                         filp->f_pos += chars;
 171                         left -= chars;
 172                         read += chars;
 173                         if (*bhe) {
 174                                 memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
 175                                 brelse(*bhe);
 176                                 buf += chars;
 177                         } else {
 178                                 while (chars-- > 0)
 179                                         put_user(0,buf++);
 180                         }
 181                         offset = 0;
 182                         if (++bhe == &buflist[NBUF])
 183                                 bhe = buflist;
 184                 } while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock));
 185         } while (left > 0);
 186 
 187 /* Release the read-ahead blocks */
 188         while (bhe != bhb) {
 189                 brelse(*bhe);
 190                 if (++bhe == &buflist[NBUF])
 191                         bhe = buflist;
 192         };
 193         if (!read)
 194                 return -EIO;
 195         filp->f_reada = 1;
 196         if (!IS_RDONLY(inode)) {
 197                 inode->i_atime = CURRENT_TIME;
 198                 inode->i_dirt = 1;
 199         }
 200         return read;
 201 }
 202 
 203 static int sysv_file_write(struct inode * inode, struct file * filp, const char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 204 {
 205         struct super_block * sb = inode->i_sb;
 206         off_t pos;
 207         int written,c;
 208         struct buffer_head * bh;
 209         char * p;
 210 
 211         if (!inode) {
 212                 printk("sysv_file_write: inode = NULL\n");
 213                 return -EINVAL;
 214         }
 215         if (!S_ISREG(inode->i_mode)) {
 216                 printk("sysv_file_write: mode = %07o\n",inode->i_mode);
 217                 return -EINVAL;
 218         }
 219 /*
 220  * ok, append may not work when many processes are writing at the same time
 221  * but so what. That way leads to madness anyway.
 222  * But we need to protect against simultaneous truncate as we may end up
 223  * writing our data into blocks that have meanwhile been incorporated into
 224  * the freelist, thereby trashing the freelist.
 225  */
 226         if (filp->f_flags & O_APPEND)
 227                 pos = inode->i_size;
 228         else
 229                 pos = filp->f_pos;
 230         written = 0;
 231         while (written<count) {
 232                 bh = sysv_getblk (inode, pos >> sb->sv_block_size_bits, 1);
 233                 if (!bh) {
 234                         if (!written)
 235                                 written = -ENOSPC;
 236                         break;
 237                 }
 238                 c = sb->sv_block_size - (pos & sb->sv_block_size_1);
 239                 if (c > count-written)
 240                         c = count-written;
 241                 if (c != sb->sv_block_size && !bh->b_uptodate) {
 242                         ll_rw_block(READ, 1, &bh);
 243                         wait_on_buffer(bh);
 244                         if (!bh->b_uptodate) {
 245                                 brelse(bh);
 246                                 if (!written)
 247                                         written = -EIO;
 248                                 break;
 249                         }
 250                 }
 251                 /* now either c==sb->sv_block_size or bh->b_uptodate */
 252                 p = (pos & sb->sv_block_size_1) + bh->b_data;
 253                 pos += c;
 254                 if (pos > inode->i_size) {
 255                         inode->i_size = pos;
 256                         inode->i_dirt = 1;
 257                 }
 258                 written += c;
 259                 memcpy_fromfs(p,buf,c);
 260                 buf += c;
 261                 bh->b_uptodate = 1;
 262                 mark_buffer_dirty(bh, 0);
 263                 brelse(bh);
 264         }
 265         inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 266         filp->f_pos = pos;
 267         inode->i_dirt = 1;
 268         return written;
 269 }

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