home *** CD-ROM | disk | FTP | other *** search
/ Whiteline: Alpha / Whiteline Alpha.iso / linux / atari / source / source.lzh / atari-linux-0.01pl3 / fs / ext2 / fsync.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-05  |  3.8 KB  |  195 lines

  1. /*
  2.  *  linux/fs/ext2/fsync.c
  3.  *
  4.  *  Copyright (C) 1993  Stephen Tweedie (sct@dcs.ed.ac.uk)
  5.  *  from
  6.  *  Copyright (C) 1992  Remy Card (card@masi.ibp.fr)
  7.  *  from
  8.  *  linux/fs/minix/truncate.c   Copyright (C) 1991, 1992  Linus Torvalds
  9.  * 
  10.  *  ext2fs fsync primitive
  11.  */
  12.  
  13. #include <asm/segment.h>
  14. #include <asm/system.h>
  15.  
  16. #include <linux/errno.h>
  17. #include <linux/fs.h>
  18. #include <linux/ext2_fs.h>
  19. #include <linux/fcntl.h>
  20. #include <linux/sched.h>
  21. #include <linux/stat.h>
  22. #include <linux/locks.h>
  23.  
  24.  
  25. #define blocksize (EXT2_BLOCK_SIZE(inode->i_sb))
  26. #define addr_per_block (EXT2_ADDR_PER_BLOCK(inode->i_sb))
  27.  
  28. static int sync_block (struct inode * inode, unsigned long * block, int wait)
  29. {
  30.     struct buffer_head * bh;
  31.     int tmp;
  32.     
  33.     if (!*block)
  34.         return 0;
  35.     tmp = *block;
  36.     bh = get_hash_table (inode->i_dev, *block, blocksize);
  37.     if (!bh)
  38.         return 0;
  39.     if (*block != tmp) {
  40.         brelse (bh);
  41.         return 1;
  42.     }
  43.     if (wait && bh->b_req && !bh->b_uptodate) {
  44.         brelse (bh);
  45.         return -1;
  46.     }
  47.     if (wait || !bh->b_uptodate || !bh->b_dirt) {
  48.         brelse (bh);
  49.         return 0;
  50.     }
  51.     ll_rw_block (WRITE, 1, &bh);
  52.     bh->b_count--;
  53.     return 0;
  54. }
  55.  
  56. static int sync_iblock (struct inode * inode, unsigned long * iblock, 
  57.             struct buffer_head ** bh, int wait) 
  58. {
  59.     int rc, tmp;
  60.     
  61.     *bh = NULL;
  62.     tmp = *iblock;
  63.     if (!tmp)
  64.         return 0;
  65.     rc = sync_block (inode, iblock, wait);
  66.     if (rc)
  67.         return rc;
  68.     *bh = bread (inode->i_dev, tmp, blocksize);
  69.     if (tmp != *iblock) {
  70.         brelse (*bh);
  71.         *bh = NULL;
  72.         return 1;
  73.     }
  74.     if (!*bh)
  75.         return -1;
  76.     return 0;
  77. }
  78.  
  79.  
  80. static int sync_direct (struct inode * inode, int wait)
  81. {
  82.     int i;
  83.     int rc, err = 0;
  84.  
  85.     for (i = 0; i < EXT2_NDIR_BLOCKS; i++) {
  86.         rc = sync_block (inode, inode->u.ext2_i.i_data + i, wait);
  87.         if (rc > 0)
  88.             break;
  89.         if (rc)
  90.             err = rc;
  91.     }
  92.     return err;
  93. }
  94.  
  95. static int sync_indirect (struct inode * inode, unsigned long * iblock,
  96.               int wait)
  97. {
  98.     int i;
  99.     struct buffer_head * ind_bh;
  100.     int rc, err = 0;
  101.  
  102.     rc = sync_iblock (inode, iblock, &ind_bh, wait);
  103.     if (rc || !ind_bh)
  104.         return rc;
  105.     
  106.     for (i = 0; i < addr_per_block; i++) {
  107.         rc = sync_block (inode, 
  108.                  ((unsigned long *) ind_bh->b_data) + i,
  109.                  wait);
  110.         if (rc > 0)
  111.             break;
  112.         if (rc)
  113.             err = rc;
  114.     }
  115.     brelse (ind_bh);
  116.     return err;
  117. }
  118.  
  119. static int sync_dindirect (struct inode * inode, unsigned long * diblock,
  120.                int wait)
  121. {
  122.     int i;
  123.     struct buffer_head * dind_bh;
  124.     int rc, err = 0;
  125.  
  126.     rc = sync_iblock (inode, diblock, &dind_bh, wait);
  127.     if (rc || !dind_bh)
  128.         return rc;
  129.     
  130.     for (i = 0; i < addr_per_block; i++) {
  131.         rc = sync_indirect (inode,
  132.                     ((unsigned long *) dind_bh->b_data) + i,
  133.                     wait);
  134.         if (rc > 0)
  135.             break;
  136.         if (rc)
  137.             err = rc;
  138.     }
  139.     brelse (dind_bh);
  140.     return err;
  141. }
  142.  
  143. static int sync_tindirect (struct inode * inode, unsigned long * tiblock, 
  144.                int wait)
  145. {
  146.     int i;
  147.     struct buffer_head * tind_bh;
  148.     int rc, err = 0;
  149.  
  150.     rc = sync_iblock (inode, tiblock, &tind_bh, wait);
  151.     if (rc || !tind_bh)
  152.         return rc;
  153.     
  154.     for (i = 0; i < addr_per_block; i++) {
  155.         rc = sync_dindirect (inode,
  156.                      ((unsigned long *) tind_bh->b_data) + i,
  157.                      wait);
  158.         if (rc > 0)
  159.             break;
  160.         if (rc)
  161.             err = rc;
  162.     }
  163.     brelse (tind_bh);
  164.     return err;
  165. }
  166.  
  167. int ext2_sync_file (struct inode * inode, struct file * file)
  168. {
  169.     int wait, err = 0;
  170.  
  171.     if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
  172.          S_ISLNK(inode->i_mode)))
  173.         return -EINVAL;
  174.     /* Don't sync fast links! */
  175.     if (S_ISLNK(inode->i_mode) && !(inode->i_blocks))
  176.         goto skip;
  177.  
  178.     for (wait=0; wait<=1; wait++)
  179.     {
  180.         err |= sync_direct (inode, wait);
  181.         err |= sync_indirect (inode,
  182.                       inode->u.ext2_i.i_data+EXT2_IND_BLOCK,
  183.                       wait);
  184.         err |= sync_dindirect (inode,
  185.                        inode->u.ext2_i.i_data+EXT2_DIND_BLOCK, 
  186.                        wait);
  187.         err |= sync_tindirect (inode, 
  188.                        inode->u.ext2_i.i_data+EXT2_TIND_BLOCK, 
  189.                        wait);
  190.     }
  191. skip:
  192.     err |= ext2_sync_inode (inode);
  193.     return (err < 0) ? -EIO : 0;
  194. }
  195.