home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.0 / LINUX-1.0 / LINUX-1 / linux / fs / ext2 / file.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-09  |  6.8 KB  |  302 lines

  1. /*
  2.  *  linux/fs/ext2/file.c
  3.  *
  4.  *  Copyright (C) 1992, 1993, 1994  Remy Card (card@masi.ibp.fr)
  5.  *                                  Laboratoire MASI - Institut Blaise Pascal
  6.  *                                  Universite Pierre et Marie Curie (Paris VI)
  7.  *
  8.  *  from
  9.  *
  10.  *  linux/fs/minix/file.c
  11.  *
  12.  *  Copyright (C) 1991, 1992  Linus Torvalds
  13.  *
  14.  *  ext2 fs regular file handling primitives
  15.  */
  16.  
  17. #include <asm/segment.h>
  18. #include <asm/system.h>
  19.  
  20. #include <linux/errno.h>
  21. #include <linux/fs.h>
  22. #include <linux/ext2_fs.h>
  23. #include <linux/fcntl.h>
  24. #include <linux/sched.h>
  25. #include <linux/stat.h>
  26. #include <linux/locks.h>
  27.  
  28. #define    NBUF    32
  29.  
  30. #define MIN(a,b) (((a)<(b))?(a):(b))
  31. #define MAX(a,b) (((a)>(b))?(a):(b))
  32.  
  33. #include <linux/fs.h>
  34. #include <linux/ext2_fs.h>
  35.  
  36. static int ext2_file_read (struct inode *, struct file *, char *, int);
  37. static int ext2_file_write (struct inode *, struct file *, char *, int);
  38. static void ext2_release_file (struct inode *, struct file *);
  39.  
  40. /*
  41.  * We have mostly NULL's here: the current defaults are ok for
  42.  * the ext2 filesystem.
  43.  */
  44. static struct file_operations ext2_file_operations = {
  45.     NULL,            /* lseek - default */
  46.     ext2_file_read,        /* read */
  47.     ext2_file_write,    /* write */
  48.     NULL,            /* readdir - bad */
  49.     NULL,            /* select - default */
  50.     ext2_ioctl,        /* ioctl */
  51.     generic_mmap,          /* mmap */
  52.     NULL,            /* no special open is needed */
  53.     ext2_release_file,    /* release */
  54.     ext2_sync_file        /* fsync */
  55. };
  56.  
  57. struct inode_operations ext2_file_inode_operations = {
  58.     &ext2_file_operations,/* default file operations */
  59.     NULL,            /* create */
  60.     NULL,            /* lookup */
  61.     NULL,            /* link */
  62.     NULL,            /* unlink */
  63.     NULL,            /* symlink */
  64.     NULL,            /* mkdir */
  65.     NULL,            /* rmdir */
  66.     NULL,            /* mknod */
  67.     NULL,            /* rename */
  68.     NULL,            /* readlink */
  69.     NULL,            /* follow_link */
  70.     ext2_bmap,        /* bmap */
  71.     ext2_truncate,        /* truncate */
  72.     ext2_permission        /* permission */
  73. };
  74.  
  75. static int ext2_file_read (struct inode * inode, struct file * filp,
  76.             char * buf, int count)
  77. {
  78.     int read, left, chars;
  79.     int block, 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.     struct super_block * sb;
  85.     unsigned int size;
  86.     int err;
  87.  
  88.     if (!inode) {
  89.         printk ("ext2_file_read: inode = NULL\n");
  90.         return -EINVAL;
  91.     }
  92.     sb = inode->i_sb;
  93.     if (!S_ISREG(inode->i_mode)) {
  94.         ext2_warning (sb, "ext2_file_read", "mode = %07o",
  95.                   inode->i_mode);
  96.         return -EINVAL;
  97.     }
  98.     offset = filp->f_pos;
  99.     size = inode->i_size;
  100.     if (offset > size)
  101.         left = 0;
  102.     else
  103.         left = size - offset;
  104.     if (left > count)
  105.         left = count;
  106.     if (left <= 0)
  107.         return 0;
  108.     read = 0;
  109.     block = offset >> EXT2_BLOCK_SIZE_BITS(sb);
  110.     offset &= (sb->s_blocksize - 1);
  111.     size = (size + sb->s_blocksize - 1) >> EXT2_BLOCK_SIZE_BITS(sb);
  112.     blocks = (left + offset + sb->s_blocksize - 1) >> EXT2_BLOCK_SIZE_BITS(sb);
  113.     bhb = bhe = buflist;
  114.     if (filp->f_reada) {
  115.         blocks += read_ahead[MAJOR(inode->i_dev)] >>
  116.             (EXT2_BLOCK_SIZE_BITS(sb) - 9);
  117.         if (block + blocks > size)
  118.             blocks = size - block;
  119.     }
  120.  
  121.     /*
  122.      * We do this in a two stage process.  We first try and request
  123.      * as many blocks as we can, then we wait for the first one to
  124.      * complete, and then we try and wrap up as many as are actually
  125.      * done.  This routine is rather generic, in that it can be used
  126.      * in a filesystem by substituting the appropriate function in
  127.      * for getblk
  128.      *
  129.      * This routine is optimized to make maximum use of the various
  130.      * buffers and caches.
  131.      */
  132.  
  133.     do {
  134.         bhrequest = 0;
  135.         uptodate = 1;
  136.         while (blocks) {
  137.             --blocks;
  138.             *bhb = ext2_getblk (inode, block++, 0, &err);
  139.             if (*bhb && !(*bhb)->b_uptodate) {
  140.                 uptodate = 0;
  141.                 bhreq[bhrequest++] = *bhb;
  142.             }
  143.  
  144.             if (++bhb == &buflist[NBUF])
  145.                 bhb = buflist;
  146.  
  147.             /*
  148.              * If the block we have on hand is uptodate, go ahead
  149.              * and complete processing
  150.              */
  151.             if (uptodate)
  152.                 break;
  153.  
  154.             if (bhb == bhe)
  155.                 break;
  156.         }
  157.  
  158.         /*
  159.          * Now request them all
  160.          */
  161.         if (bhrequest)
  162.             ll_rw_block (READ, bhrequest, bhreq);
  163.  
  164.         do {
  165.             /*
  166.              * Finish off all I/O that has actually completed
  167.              */
  168.             if (*bhe) {
  169.                 wait_on_buffer (*bhe);
  170.                 if (!(*bhe)->b_uptodate) { /* read error? */
  171.                         brelse(*bhe);
  172.                     if (++bhe == &buflist[NBUF])
  173.                       bhe = buflist;
  174.                     left = 0;
  175.                     break;
  176.                 }
  177.             }
  178.             if (left < sb->s_blocksize - offset)
  179.                 chars = left;
  180.             else
  181.                 chars = sb->s_blocksize - offset;
  182.             filp->f_pos += chars;
  183.             left -= chars;
  184.             read += chars;
  185.             if (*bhe) {
  186.                 memcpy_tofs (buf, offset + (*bhe)->b_data,
  187.                          chars);
  188.                 brelse (*bhe);
  189.                 buf += chars;
  190.             } else {
  191.                 while (chars-- > 0)
  192.                     put_fs_byte (0, buf++);
  193.             }
  194.             offset = 0;
  195.             if (++bhe == &buflist[NBUF])
  196.                 bhe = buflist;
  197.         } while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock));
  198.     } while (left > 0);
  199.  
  200.     /*
  201.      * Release the read-ahead blocks
  202.      */
  203.     while (bhe != bhb) {
  204.         brelse (*bhe);
  205.         if (++bhe == &buflist[NBUF])
  206.             bhe = buflist;
  207.     }
  208.     if (!read)
  209.         return -EIO;
  210.     filp->f_reada = 1;
  211.     if (!IS_RDONLY(inode)) {
  212.         inode->i_atime = CURRENT_TIME;
  213.         inode->i_dirt = 1;
  214.     }
  215.     return read;
  216. }
  217.  
  218. static int ext2_file_write (struct inode * inode, struct file * filp,
  219.                 char * buf, int count)
  220. {
  221.     off_t pos;
  222.     int written, c;
  223.     struct buffer_head * bh;
  224.     char * p;
  225.     struct super_block * sb;
  226.     int err;
  227.  
  228.     if (!inode) {
  229.         printk("ext2_file_write: inode = NULL\n");
  230.         return -EINVAL;
  231.     }
  232.     sb = inode->i_sb;
  233.     if (sb->s_flags & MS_RDONLY)
  234.         /*
  235.          * This fs has been automatically remounted ro because of errors
  236.          */
  237.         return -ENOSPC;
  238.  
  239.     if (!S_ISREG(inode->i_mode)) {
  240.         ext2_warning (sb, "ext2_file_write", "mode = %07o\n",
  241.                   inode->i_mode);
  242.         return -EINVAL;
  243.     }
  244. /*
  245.  * ok, append may not work when many processes are writing at the same time
  246.  * but so what. That way leads to madness anyway.
  247.  */
  248.     if (filp->f_flags & O_APPEND)
  249.         pos = inode->i_size;
  250.     else
  251.         pos = filp->f_pos;
  252.     written = 0;
  253.     while (written < count) {
  254.         bh = ext2_getblk (inode, pos / sb->s_blocksize, 1, &err);
  255.         if (!bh) {
  256.             if (!written)
  257.                 written = err;
  258.             break;
  259.         }
  260.         c = sb->s_blocksize - (pos % sb->s_blocksize);
  261.         if (c > count-written)
  262.             c = count - written;
  263.         if (c != sb->s_blocksize && !bh->b_uptodate) {
  264.             ll_rw_block (READ, 1, &bh);
  265.             wait_on_buffer (bh);
  266.             if (!bh->b_uptodate) {
  267.                 brelse (bh);
  268.                 if (!written)
  269.                     written = -EIO;
  270.                 break;
  271.             }
  272.         }
  273.         p = (pos % sb->s_blocksize) + bh->b_data;
  274.         pos += c;
  275.         if (pos > inode->i_size) {
  276.             inode->i_size = pos;
  277.             inode->i_dirt = 1;
  278.         }
  279.         written += c;
  280.         memcpy_fromfs (p, buf, c);
  281.         buf += c;
  282.         bh->b_uptodate = 1;
  283.         bh->b_dirt = 1;
  284.         brelse (bh);
  285.     }
  286.     inode->i_ctime = inode->i_mtime = CURRENT_TIME;
  287.     filp->f_pos = pos;
  288.     inode->i_dirt = 1;
  289.     return written;
  290. }
  291.  
  292. /*
  293.  * Called when a inode is released. Note that this is different
  294.  * from ext2_open: open gets called at every open, but release
  295.  * gets called only when /all/ the files are closed.
  296.  */
  297. static void ext2_release_file (struct inode * inode, struct file * filp)
  298. {
  299.     if (filp->f_mode & 2)
  300.         ext2_discard_prealloc (inode);
  301. }
  302.