home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / fs / ext2 / file.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-26  |  8.2 KB  |  355 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.     NULL,            /* fasync */
  56.     NULL,            /* check_media_change */
  57.     NULL            /* revalidate */
  58. };
  59.  
  60. struct inode_operations ext2_file_inode_operations = {
  61.     &ext2_file_operations,/* default file operations */
  62.     NULL,            /* create */
  63.     NULL,            /* lookup */
  64.     NULL,            /* link */
  65.     NULL,            /* unlink */
  66.     NULL,            /* symlink */
  67.     NULL,            /* mkdir */
  68.     NULL,            /* rmdir */
  69.     NULL,            /* mknod */
  70.     NULL,            /* rename */
  71.     NULL,            /* readlink */
  72.     NULL,            /* follow_link */
  73.     ext2_bmap,        /* bmap */
  74.     ext2_truncate,        /* truncate */
  75.     ext2_permission,    /* permission */
  76.     NULL            /* smap */
  77. };
  78.  
  79. static int ext2_file_read (struct inode * inode, struct file * filp,
  80.             char * buf, int count)
  81. {
  82.     int read, left, chars;
  83.     int block, blocks, offset;
  84.     int bhrequest, uptodate;
  85.     int clusterblocks;
  86.     struct buffer_head ** bhb, ** bhe;
  87.     struct buffer_head * bhreq[NBUF];
  88.     struct buffer_head * buflist[NBUF];
  89.     struct super_block * sb;
  90.     unsigned int size;
  91.     int err;
  92.  
  93.     if (!inode) {
  94.         printk ("ext2_file_read: inode = NULL\n");
  95.         return -EINVAL;
  96.     }
  97.     sb = inode->i_sb;
  98.     if (!S_ISREG(inode->i_mode)) {
  99.         ext2_warning (sb, "ext2_file_read", "mode = %07o",
  100.                   inode->i_mode);
  101.         return -EINVAL;
  102.     }
  103.     offset = filp->f_pos;
  104.     size = inode->i_size;
  105.     if (offset > size)
  106.         left = 0;
  107.     else
  108.         left = size - offset;
  109.     if (left > count)
  110.         left = count;
  111.     if (left <= 0)
  112.         return 0;
  113.     read = 0;
  114.     block = offset >> EXT2_BLOCK_SIZE_BITS(sb);
  115.     offset &= (sb->s_blocksize - 1);
  116.     size = (size + sb->s_blocksize - 1) >> EXT2_BLOCK_SIZE_BITS(sb);
  117.     blocks = (left + offset + sb->s_blocksize - 1) >> EXT2_BLOCK_SIZE_BITS(sb);
  118.     bhb = bhe = buflist;
  119.     if (filp->f_reada) {
  120.             if (blocks < read_ahead[MAJOR(inode->i_dev)] >> (EXT2_BLOCK_SIZE_BITS(sb) - 9))
  121.                 blocks = read_ahead[MAJOR(inode->i_dev)] >> (EXT2_BLOCK_SIZE_BITS(sb) - 9);
  122.         if (block + blocks > size)
  123.             blocks = size - block;
  124.     }
  125.  
  126.     /*
  127.      * We do this in a two stage process.  We first try and request
  128.      * as many blocks as we can, then we wait for the first one to
  129.      * complete, and then we try and wrap up as many as are actually
  130.      * done.  This routine is rather generic, in that it can be used
  131.      * in a filesystem by substituting the appropriate function in
  132.      * for getblk
  133.      *
  134.      * This routine is optimized to make maximum use of the various
  135.      * buffers and caches.
  136.      */
  137.  
  138.     clusterblocks = 0;
  139.  
  140.     do {
  141.         bhrequest = 0;
  142.         uptodate = 1;
  143.         while (blocks) {
  144.             --blocks;
  145. #if 1
  146.             if(!clusterblocks) clusterblocks = ext2_getcluster(inode, block);
  147.             if(clusterblocks) clusterblocks--;
  148. #endif
  149.  
  150.             *bhb = ext2_getblk (inode, block++, 0, &err);
  151.             if (*bhb && !(*bhb)->b_uptodate) {
  152.                 uptodate = 0;
  153.                 bhreq[bhrequest++] = *bhb;
  154.             }
  155.  
  156.             if (++bhb == &buflist[NBUF])
  157.                 bhb = buflist;
  158.  
  159.             /*
  160.              * If the block we have on hand is uptodate, go ahead
  161.              * and complete processing
  162.              */
  163.             if (uptodate)
  164.                 break;
  165.  
  166.             if (bhb == bhe)
  167.                 break;
  168.         }
  169.  
  170.         /*
  171.          * Now request them all
  172.          */
  173.         if (bhrequest)
  174.             ll_rw_block (READ, bhrequest, bhreq);
  175.  
  176.         do {
  177.             /*
  178.              * Finish off all I/O that has actually completed
  179.              */
  180.             if (*bhe) {
  181.                 wait_on_buffer (*bhe);
  182.                 if (!(*bhe)->b_uptodate) { /* read error? */
  183.                         brelse(*bhe);
  184.                     if (++bhe == &buflist[NBUF])
  185.                       bhe = buflist;
  186.                     left = 0;
  187.                     break;
  188.                 }
  189.             }
  190.             if (left < sb->s_blocksize - offset)
  191.                 chars = left;
  192.             else
  193.                 chars = sb->s_blocksize - offset;
  194.             filp->f_pos += chars;
  195.             left -= chars;
  196.             read += chars;
  197.             if (*bhe) {
  198.                 memcpy_tofs (buf, offset + (*bhe)->b_data,
  199.                          chars);
  200.                 brelse (*bhe);
  201.                 buf += chars;
  202.             } else {
  203.                 while (chars-- > 0)
  204.                     put_fs_byte (0, buf++);
  205.             }
  206.             offset = 0;
  207.             if (++bhe == &buflist[NBUF])
  208.                 bhe = buflist;
  209.         } while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock));
  210.     } while (left > 0);
  211.  
  212.     /*
  213.      * Release the read-ahead blocks
  214.      */
  215.     while (bhe != bhb) {
  216.         brelse (*bhe);
  217.         if (++bhe == &buflist[NBUF])
  218.             bhe = buflist;
  219.     }
  220.     if (!read)
  221.         return -EIO;
  222.     filp->f_reada = 1;
  223.     if (!IS_RDONLY(inode)) {
  224.         inode->i_atime = CURRENT_TIME;
  225.         inode->i_dirt = 1;
  226.     }
  227.     return read;
  228. }
  229.  
  230. static int ext2_file_write (struct inode * inode, struct file * filp,
  231.                 char * buf, int count)
  232. {
  233.     const loff_t two_gb = 2147483647;
  234.     loff_t pos;
  235.     off_t pos2;
  236.     int written, c;
  237.     struct buffer_head * bh, *bufferlist[NBUF];
  238.     char * p;
  239.     struct super_block * sb;
  240.     int err;
  241.     int i,buffercount,write_error;
  242.  
  243.     write_error = buffercount = 0;
  244.     if (!inode) {
  245.         printk("ext2_file_write: inode = NULL\n");
  246.         return -EINVAL;
  247.     }
  248.     sb = inode->i_sb;
  249.     if (sb->s_flags & MS_RDONLY)
  250.         /*
  251.          * This fs has been automatically remounted ro because of errors
  252.          */
  253.         return -ENOSPC;
  254.  
  255.     if (!S_ISREG(inode->i_mode)) {
  256.         ext2_warning (sb, "ext2_file_write", "mode = %07o",
  257.                   inode->i_mode);
  258.         return -EINVAL;
  259.     }
  260.     down(&inode->i_sem);
  261.     if (filp->f_flags & O_APPEND)
  262.         pos = inode->i_size;
  263.     else
  264.         pos = filp->f_pos;
  265.     pos2 = (off_t) pos;
  266.     /*
  267.      * If a file has been opened in synchronous mode, we have to ensure
  268.      * that meta-data will also be written synchronously.  Thus, we
  269.      * set the i_osync field.  This field is tested by the allocation
  270.      * routines.
  271.      */
  272.     if (filp->f_flags & O_SYNC)
  273.         inode->u.ext2_i.i_osync++;
  274.     written = 0;
  275.     while (written < count) {
  276.         if (pos > two_gb) {
  277.             if (!written)
  278.                 written = -EFBIG;
  279.             break;
  280.         }
  281.         bh = ext2_getblk (inode, pos2 / sb->s_blocksize, 1, &err);
  282.         if (!bh) {
  283.             if (!written)
  284.                 written = err;
  285.             break;
  286.         }
  287.         c = sb->s_blocksize - (pos2 % sb->s_blocksize);
  288.         if (c > count-written)
  289.             c = count - written;
  290.         if (c != sb->s_blocksize && !bh->b_uptodate) {
  291.             ll_rw_block (READ, 1, &bh);
  292.             wait_on_buffer (bh);
  293.             if (!bh->b_uptodate) {
  294.                 brelse (bh);
  295.                 if (!written)
  296.                     written = -EIO;
  297.                 break;
  298.             }
  299.         }
  300.         p = (pos2 % sb->s_blocksize) + bh->b_data;
  301.         pos2 += c;
  302.         pos += c;
  303.         written += c;
  304.         memcpy_fromfs (p, buf, c);
  305.         buf += c;
  306.         bh->b_uptodate = 1;
  307.         mark_buffer_dirty(bh, 0);
  308.         if (filp->f_flags & O_SYNC)
  309.             bufferlist[buffercount++] = bh;
  310.         else
  311.             brelse(bh);
  312.         if (buffercount == NBUF){
  313.             ll_rw_block(WRITE, buffercount, bufferlist);
  314.             for(i=0; i<buffercount; i++){
  315.                 wait_on_buffer(bufferlist[i]);
  316.                 if (!bufferlist[i]->b_uptodate)
  317.                     write_error=1;
  318.                 brelse(bufferlist[i]);
  319.             }
  320.             buffercount=0;
  321.         }
  322.         if(write_error)
  323.             break;
  324.     }
  325.     if ( buffercount ){
  326.         ll_rw_block(WRITE, buffercount, bufferlist);
  327.         for(i=0; i<buffercount; i++){
  328.             wait_on_buffer(bufferlist[i]);
  329.             if (!bufferlist[i]->b_uptodate)
  330.                 write_error=1;
  331.             brelse(bufferlist[i]);
  332.         }
  333.     }        
  334.     if (pos > inode->i_size)
  335.         inode->i_size = pos;
  336.     if (filp->f_flags & O_SYNC)
  337.         inode->u.ext2_i.i_osync--;
  338.     up(&inode->i_sem);
  339.     inode->i_ctime = inode->i_mtime = CURRENT_TIME;
  340.     filp->f_pos = pos;
  341.     inode->i_dirt = 1;
  342.     return written;
  343. }
  344.  
  345. /*
  346.  * Called when a inode is released. Note that this is different
  347.  * from ext2_open: open gets called at every open, but release
  348.  * gets called only when /all/ the files are closed.
  349.  */
  350. static void ext2_release_file (struct inode * inode, struct file * filp)
  351. {
  352.     if (filp->f_mode & 2)
  353.         ext2_discard_prealloc (inode);
  354. }
  355.