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 / ext / truncate.c < prev   
Encoding:
C/C++ Source or Header  |  1993-12-27  |  5.2 KB  |  253 lines

  1. /*
  2.  *  linux/fs/ext/truncate.c
  3.  *
  4.  *  Copyright (C) 1992  Remy Card (card@masi.ibp.fr)
  5.  *
  6.  *  from
  7.  *
  8.  *  linux/fs/minix/truncate.c
  9.  *
  10.  *  Copyright (C) 1991, 1992  Linus Torvalds
  11.  */
  12.  
  13. #include <linux/sched.h>
  14. #include <linux/ext_fs.h>
  15. #include <linux/stat.h>
  16. #include <linux/fcntl.h>
  17. #include <linux/errno.h>
  18.  
  19. /*
  20.  * Truncate has the most races in the whole filesystem: coding it is
  21.  * a pain in the a**. Especially as I don't do any locking...
  22.  *
  23.  * The code may look a bit weird, but that's just because I've tried to
  24.  * handle things like file-size changes in a somewhat graceful manner.
  25.  * Anyway, truncating a file at the same time somebody else writes to it
  26.  * is likely to result in pretty weird behaviour...
  27.  *
  28.  * The new code handles normal truncates (size = 0) as well as the more
  29.  * general case (size = XXX). I hope.
  30.  */
  31.  
  32. static int trunc_direct(struct inode * inode)
  33. {
  34.     int i, tmp;
  35.     unsigned long * p;
  36.     struct buffer_head * bh;
  37.     int retry = 0;
  38. #define DIRECT_BLOCK ((inode->i_size + 1023) >> 10)
  39.  
  40. repeat:
  41.     for (i = DIRECT_BLOCK ; i < 9 ; i++) {
  42.         p = inode->u.ext_i.i_data+i;
  43.         if (!(tmp = *p))
  44.             continue;
  45.         bh = getblk(inode->i_dev,tmp,BLOCK_SIZE);
  46.         if (i < DIRECT_BLOCK) {
  47.             brelse(bh);
  48.             goto repeat;
  49.         }
  50.         if ((bh && bh->b_count != 1) || tmp != *p) {
  51.             retry = 1;
  52.             brelse(bh);
  53.             continue;
  54.         }
  55.         *p = 0;
  56.         inode->i_dirt = 1;
  57.         brelse(bh);
  58.         ext_free_block(inode->i_sb,tmp);
  59.     }
  60.     return retry;
  61. }
  62.  
  63. static int trunc_indirect(struct inode * inode, int offset, unsigned long * p)
  64. {
  65.     int i, tmp;
  66.     struct buffer_head * bh;
  67.     struct buffer_head * ind_bh;
  68.     unsigned long * ind;
  69.     int retry = 0;
  70. #define INDIRECT_BLOCK (DIRECT_BLOCK-offset)
  71.  
  72.     tmp = *p;
  73.     if (!tmp)
  74.         return 0;
  75.     ind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
  76.     if (tmp != *p) {
  77.         brelse(ind_bh);
  78.         return 1;
  79.     }
  80.     if (!ind_bh) {
  81.         *p = 0;
  82.         return 0;
  83.     }
  84. repeat:
  85.     for (i = INDIRECT_BLOCK ; i < 256 ; i++) {
  86.         if (i < 0)
  87.             i = 0;
  88.         if (i < INDIRECT_BLOCK)
  89.             goto repeat;
  90.         ind = i+(unsigned long *) ind_bh->b_data;
  91.         tmp = *ind;
  92.         if (!tmp)
  93.             continue;
  94.         bh = getblk(inode->i_dev,tmp,BLOCK_SIZE);
  95.         if (i < INDIRECT_BLOCK) {
  96.             brelse(bh);
  97.             goto repeat;
  98.         }
  99.         if ((bh && bh->b_count != 1) || tmp != *ind) {
  100.             retry = 1;
  101.             brelse(bh);
  102.             continue;
  103.         }
  104.         *ind = 0;
  105.         ind_bh->b_dirt = 1;
  106.         brelse(bh);
  107.         ext_free_block(inode->i_sb,tmp);
  108.     }
  109.     ind = (unsigned long *) ind_bh->b_data;
  110.     for (i = 0; i < 256; i++)
  111.         if (*(ind++))
  112.             break;
  113.     if (i >= 256)
  114.         if (ind_bh->b_count != 1)
  115.             retry = 1;
  116.         else {
  117.             tmp = *p;
  118.             *p = 0;
  119.             inode->i_dirt = 1;
  120.             ext_free_block(inode->i_sb,tmp);
  121.         }
  122.     brelse(ind_bh);
  123.     return retry;
  124. }
  125.  
  126. static int trunc_dindirect(struct inode * inode, int offset, unsigned long * p)
  127. {
  128.     int i,tmp;
  129.     struct buffer_head * dind_bh;
  130.     unsigned long * dind;
  131.     int retry = 0;
  132. #define DINDIRECT_BLOCK ((DIRECT_BLOCK-offset)>>8)
  133.  
  134.     tmp = *p;
  135.     if (!tmp)
  136.         return 0;
  137.     dind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
  138.     if (tmp != *p) {
  139.         brelse(dind_bh);
  140.         return 1;
  141.     }
  142.     if (!dind_bh) {
  143.         *p = 0;
  144.         return 0;
  145.     }
  146. repeat:
  147.     for (i = DINDIRECT_BLOCK ; i < 256 ; i ++) {
  148.         if (i < 0)
  149.             i = 0;
  150.         if (i < DINDIRECT_BLOCK)
  151.             goto repeat;
  152.         dind = i+(unsigned long *) dind_bh->b_data;
  153.         tmp = *dind;
  154.         if (!tmp)
  155.             continue;
  156.         retry |= trunc_indirect(inode,offset+(i<<8),dind);
  157.         dind_bh->b_dirt = 1;
  158.     }
  159.     dind = (unsigned long *) dind_bh->b_data;
  160.     for (i = 0; i < 256; i++)
  161.         if (*(dind++))
  162.             break;
  163.     if (i >= 256)
  164.         if (dind_bh->b_count != 1)
  165.             retry = 1;
  166.         else {
  167.             tmp = *p;
  168.             *p = 0;
  169.             inode->i_dirt = 1;
  170.             ext_free_block(inode->i_sb,tmp);
  171.         }
  172.     brelse(dind_bh);
  173.     return retry;
  174. }
  175.  
  176. static int trunc_tindirect(struct inode * inode)
  177. {
  178.     int i,tmp;
  179.     struct buffer_head * tind_bh;
  180.     unsigned long * tind, * p;
  181.     int retry = 0;
  182. #define TINDIRECT_BLOCK ((DIRECT_BLOCK-(256*256+256+9))>>16)
  183.  
  184.     p = inode->u.ext_i.i_data+11;
  185.     if (!(tmp = *p))
  186.         return 0;
  187.     tind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
  188.     if (tmp != *p) {
  189.         brelse(tind_bh);
  190.         return 1;
  191.     }
  192.     if (!tind_bh) {
  193.         *p = 0;
  194.         return 0;
  195.     }
  196. repeat:
  197.     for (i = TINDIRECT_BLOCK ; i < 256 ; i ++) {
  198.         if (i < 0)
  199.             i = 0;
  200.         if (i < TINDIRECT_BLOCK)
  201.             goto repeat;
  202.         tind = i+(unsigned long *) tind_bh->b_data;
  203.         retry |= trunc_dindirect(inode,9+256+256*256+(i<<16),tind);
  204.         tind_bh->b_dirt = 1;
  205.     }
  206.     tind = (unsigned long *) tind_bh->b_data;
  207.     for (i = 0; i < 256; i++)
  208.         if (*(tind++))
  209.             break;
  210.     if (i >= 256)
  211.         if (tind_bh->b_count != 1)
  212.             retry = 1;
  213.         else {
  214.             tmp = *p;
  215.             *p = 0;
  216.             inode->i_dirt = 1;
  217.             ext_free_block(inode->i_sb,tmp);
  218.         }
  219.     brelse(tind_bh);
  220.     return retry;
  221. }
  222.  
  223. void ext_truncate(struct inode * inode)
  224. {
  225.     int retry;
  226.  
  227.     if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
  228.          S_ISLNK(inode->i_mode)))
  229.         return;
  230.     while (1) {
  231.         retry = trunc_direct(inode);
  232.         retry |= trunc_indirect(inode,9,inode->u.ext_i.i_data+9);
  233.         retry |= trunc_dindirect(inode,9+256,inode->u.ext_i.i_data+10);
  234.         retry |= trunc_tindirect(inode);
  235.         if (!retry)
  236.             break;
  237.         current->counter = 0;
  238.         schedule();
  239.     }
  240.     inode->i_mtime = inode->i_ctime = CURRENT_TIME;
  241.     inode->i_dirt = 1;
  242. }
  243.  
  244. /*
  245.  * Called when a inode is released. Note that this is different
  246.  * from ext_open: open gets called at every open, but release
  247.  * gets called only when /all/ the files are closed.
  248.  */
  249. void ext_release(struct inode * inode, struct file * filp)
  250. {
  251.     printk("ext_release not implemented\n");
  252. }
  253.