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 / truncate.c < prev   
Encoding:
C/C++ Source or Header  |  1994-02-22  |  8.6 KB  |  355 lines

  1. /*
  2.  *  linux/fs/ext2/truncate.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/truncate.c
  11.  *
  12.  *  Copyright (C) 1991, 1992  Linus Torvalds
  13.  */
  14.  
  15. /*
  16.  * Real random numbers for secure rm added 94/02/18
  17.  * Idea from Pierre del Perugia <delperug@gla.ecoledoc.ibp.fr>
  18.  */
  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 clear_block(addr,size,value) \
  29.     __asm__("cld\n\t" \
  30.         "rep\n\t" \
  31.         "stosl" \
  32.         : \
  33.         :"a" (value), "c" (size / 4), "D" ((long) (addr)) \
  34.         :"cx", "di")
  35.  
  36. static int ext2_secrm_seed = 152;    /* Random generator base */
  37.  
  38. #define RANDOM_INT (ext2_secrm_seed = ext2_secrm_seed * 69069l +1)
  39.  
  40. /*
  41.  * Truncate has the most races in the whole filesystem: coding it is
  42.  * a pain in the a**. Especially as I don't do any locking...
  43.  *
  44.  * The code may look a bit weird, but that's just because I've tried to
  45.  * handle things like file-size changes in a somewhat graceful manner.
  46.  * Anyway, truncating a file at the same time somebody else writes to it
  47.  * is likely to result in pretty weird behaviour...
  48.  *
  49.  * The new code handles normal truncates (size = 0) as well as the more
  50.  * general case (size = XXX). I hope.
  51.  */
  52.  
  53. static int trunc_direct (struct inode * inode)
  54. {
  55.     int i, tmp;
  56.     unsigned long * p;
  57.     struct buffer_head * bh;
  58.     unsigned long block_to_free = 0;
  59.     unsigned long free_count = 0;
  60.     int retry = 0;
  61.     int blocks = inode->i_sb->s_blocksize / 512;
  62. #define DIRECT_BLOCK ((inode->i_size + inode->i_sb->s_blocksize - 1) / \
  63.             inode->i_sb->s_blocksize)
  64.     int direct_block = DIRECT_BLOCK;
  65.  
  66. repeat:
  67.     for (i = direct_block ; i < EXT2_NDIR_BLOCKS ; i++) {
  68.         p = inode->u.ext2_i.i_data + i;
  69.         tmp = *p;
  70.         if (!tmp)
  71.             continue;
  72.         if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL)
  73.             bh = getblk (inode->i_dev, tmp,
  74.                      inode->i_sb->s_blocksize);
  75.         else
  76.             bh = get_hash_table (inode->i_dev, tmp,
  77.                          inode->i_sb->s_blocksize);
  78.         if (i < direct_block) {
  79.             brelse (bh);
  80.             goto repeat;
  81.         }
  82.         if ((bh && bh->b_count != 1) || tmp != *p) {
  83.             retry = 1;
  84.             brelse (bh);
  85.             continue;
  86.         }
  87.         *p = 0;
  88.         inode->i_blocks -= blocks;
  89.         inode->i_dirt = 1;
  90.         if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL) {
  91.             clear_block (bh->b_data, inode->i_sb->s_blocksize,
  92.                      RANDOM_INT);
  93.             bh->b_dirt = 1;
  94.         }
  95.         brelse (bh);
  96.         if (free_count == 0) {
  97.             block_to_free = tmp;
  98.             free_count++;
  99.         } else if (free_count > 0 && block_to_free == tmp - free_count)
  100.             free_count++;
  101.         else {
  102.             ext2_free_blocks (inode->i_sb, block_to_free, free_count);
  103.             block_to_free = tmp;
  104.             free_count = 1;
  105.         }
  106. /*        ext2_free_blocks (inode->i_sb, tmp, 1); */
  107.     }
  108.     if (free_count > 0)
  109.         ext2_free_blocks (inode->i_sb, block_to_free, free_count);
  110.     return retry;
  111. }
  112.  
  113. static int trunc_indirect (struct inode * inode, int offset, unsigned long * p)
  114. {
  115.     int i, tmp;
  116.     struct buffer_head * bh;
  117.     struct buffer_head * ind_bh;
  118.     unsigned long * ind;
  119.     unsigned long block_to_free = 0;
  120.     unsigned long free_count = 0;
  121.     int retry = 0;
  122.     int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
  123.     int blocks = inode->i_sb->s_blocksize / 512;
  124. #define INDIRECT_BLOCK ((int)DIRECT_BLOCK - offset)
  125.     int indirect_block = INDIRECT_BLOCK;
  126.  
  127.     tmp = *p;
  128.     if (!tmp)
  129.         return 0;
  130.     ind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
  131.     if (tmp != *p) {
  132.         brelse (ind_bh);
  133.         return 1;
  134.     }
  135.     if (!ind_bh) {
  136.         *p = 0;
  137.         return 0;
  138.     }
  139. repeat:
  140.     for (i = indirect_block ; i < addr_per_block ; i++) {
  141.         if (i < 0)
  142.             i = 0;
  143.         if (i < indirect_block)
  144.             goto repeat;
  145.         ind = i + (unsigned long *) ind_bh->b_data;
  146.         tmp = *ind;
  147.         if (!tmp)
  148.             continue;
  149.         if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL)
  150.             bh = getblk (inode->i_dev, tmp,
  151.                      inode->i_sb->s_blocksize);
  152.         else
  153.             bh = get_hash_table (inode->i_dev, tmp,
  154.                          inode->i_sb->s_blocksize);
  155.         if (i < indirect_block) {
  156.             brelse (bh);
  157.             goto repeat;
  158.         }
  159.         if ((bh && bh->b_count != 1) || tmp != *ind) {
  160.             retry = 1;
  161.             brelse (bh);
  162.             continue;
  163.         }
  164.         *ind = 0;
  165.         ind_bh->b_dirt = 1;
  166.         if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL) {
  167.             clear_block (bh->b_data, inode->i_sb->s_blocksize,
  168.                      RANDOM_INT);
  169.             bh->b_dirt = 1;
  170.         }
  171.         brelse (bh);
  172.         if (free_count == 0) {
  173.             block_to_free = tmp;
  174.             free_count++;
  175.         } else if (free_count > 0 && block_to_free == tmp - free_count)
  176.             free_count++;
  177.         else {
  178.             ext2_free_blocks (inode->i_sb, block_to_free, free_count);
  179.             block_to_free = tmp;
  180.             free_count = 1;
  181.         }
  182. /*        ext2_free_blocks (inode->i_sb, tmp, 1); */
  183.         inode->i_blocks -= blocks;
  184.         inode->i_dirt = 1;
  185.     }
  186.     if (free_count > 0)
  187.         ext2_free_blocks (inode->i_sb, block_to_free, free_count);
  188.     ind = (unsigned long *) ind_bh->b_data;
  189.     for (i = 0; i < addr_per_block; i++)
  190.         if (*(ind++))
  191.             break;
  192.     if (i >= addr_per_block)
  193.         if (ind_bh->b_count != 1)
  194.             retry = 1;
  195.         else {
  196.             tmp = *p;
  197.             *p = 0;
  198.             inode->i_blocks -= blocks;
  199.             inode->i_dirt = 1;
  200.             ext2_free_blocks (inode->i_sb, tmp, 1);
  201.         }
  202.     if (IS_SYNC(inode) && ind_bh->b_dirt) {
  203.         ll_rw_block (WRITE, 1, &ind_bh);
  204.         wait_on_buffer (ind_bh);
  205.     }
  206.     brelse (ind_bh);
  207.     return retry;
  208. }
  209.  
  210. static int trunc_dindirect (struct inode * inode, int offset,
  211.                 unsigned long * p)
  212. {
  213.     int i, tmp;
  214.     struct buffer_head * dind_bh;
  215.     unsigned long * dind;
  216.     int retry = 0;
  217.     int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
  218.     int blocks = inode->i_sb->s_blocksize / 512;
  219. #define DINDIRECT_BLOCK (((int)DIRECT_BLOCK - offset) / addr_per_block)
  220.     int dindirect_block = DINDIRECT_BLOCK;
  221.  
  222.     tmp = *p;
  223.     if (!tmp)
  224.         return 0;
  225.     dind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
  226.     if (tmp != *p) {
  227.         brelse (dind_bh);
  228.         return 1;
  229.     }
  230.     if (!dind_bh) {
  231.         *p = 0;
  232.         return 0;
  233.     }
  234. repeat:
  235.     for (i = dindirect_block ; i < addr_per_block ; i++) {
  236.         if (i < 0)
  237.             i = 0;
  238.         if (i < dindirect_block)
  239.             goto repeat;
  240.         dind = i + (unsigned long *) dind_bh->b_data;
  241.         tmp = *dind;
  242.         if (!tmp)
  243.             continue;
  244.         retry |= trunc_indirect (inode, offset + (i * addr_per_block),
  245.                       dind);
  246.         dind_bh->b_dirt = 1;
  247.     }
  248.     dind = (unsigned long *) dind_bh->b_data;
  249.     for (i = 0; i < addr_per_block; i++)
  250.         if (*(dind++))
  251.             break;
  252.     if (i >= addr_per_block)
  253.         if (dind_bh->b_count != 1)
  254.             retry = 1;
  255.         else {
  256.             tmp = *p;
  257.             *p = 0;
  258.             inode->i_blocks -= blocks;
  259.             inode->i_dirt = 1;
  260.             ext2_free_blocks (inode->i_sb, tmp, 1);
  261.         }
  262.     if (IS_SYNC(inode) && dind_bh->b_dirt) {
  263.         ll_rw_block (WRITE, 1, &dind_bh);
  264.         wait_on_buffer (dind_bh);
  265.     }
  266.     brelse (dind_bh);
  267.     return retry;
  268. }
  269.  
  270. static int trunc_tindirect (struct inode * inode)
  271. {
  272.     int i, tmp;
  273.     struct buffer_head * tind_bh;
  274.     unsigned long * tind, * p;
  275.     int retry = 0;
  276.     int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
  277.     int blocks = inode->i_sb->s_blocksize / 512;
  278. #define TINDIRECT_BLOCK (((int)DIRECT_BLOCK - (addr_per_block * addr_per_block + \
  279.               addr_per_block + EXT2_NDIR_BLOCKS)) / \
  280.               (addr_per_block * addr_per_block))
  281.     int tindirect_block = TINDIRECT_BLOCK;
  282.  
  283.     p = inode->u.ext2_i.i_data + EXT2_TIND_BLOCK;
  284.     if (!(tmp = *p))
  285.         return 0;
  286.     tind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
  287.     if (tmp != *p) {
  288.         brelse (tind_bh);
  289.         return 1;
  290.     }
  291.     if (!tind_bh) {
  292.         *p = 0;
  293.         return 0;
  294.     }
  295. repeat:
  296.     for (i = tindirect_block ; i < addr_per_block ; i++) {
  297.         if (i < 0)
  298.             i = 0;
  299.         if (i < tindirect_block)
  300.             goto repeat;
  301.         tind = i + (unsigned long *) tind_bh->b_data;
  302.         retry |= trunc_dindirect(inode, EXT2_NDIR_BLOCKS +
  303.             addr_per_block + (i + 1) * addr_per_block * addr_per_block,
  304.             tind);
  305.         tind_bh->b_dirt = 1;
  306.     }
  307.     tind = (unsigned long *) tind_bh->b_data;
  308.     for (i = 0; i < addr_per_block; i++)
  309.         if (*(tind++))
  310.             break;
  311.     if (i >= addr_per_block)
  312.         if (tind_bh->b_count != 1)
  313.             retry = 1;
  314.         else {
  315.             tmp = *p;
  316.             *p = 0;
  317.             inode->i_blocks -= blocks;
  318.             inode->i_dirt = 1;
  319.             ext2_free_blocks (inode->i_sb, tmp, 1);
  320.         }
  321.     if (IS_SYNC(inode) && tind_bh->b_dirt) {
  322.         ll_rw_block (WRITE, 1, &tind_bh);
  323.         wait_on_buffer (tind_bh);
  324.     }
  325.     brelse (tind_bh);
  326.     return retry;
  327. }
  328.         
  329. void ext2_truncate (struct inode * inode)
  330. {
  331.     int retry;
  332.  
  333.     if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
  334.         S_ISLNK(inode->i_mode)))
  335.         return;
  336.     ext2_discard_prealloc(inode);
  337.     while (1) {
  338.         retry = trunc_direct(inode);
  339.         retry |= trunc_indirect (inode, EXT2_IND_BLOCK,
  340.             (unsigned long *) &inode->u.ext2_i.i_data[EXT2_IND_BLOCK]);
  341.         retry |= trunc_dindirect (inode, EXT2_IND_BLOCK +
  342.             EXT2_ADDR_PER_BLOCK(inode->i_sb),
  343.             (unsigned long *) &inode->u.ext2_i.i_data[EXT2_DIND_BLOCK]);
  344.         retry |= trunc_tindirect (inode);
  345.         if (!retry)
  346.             break;
  347.         if (IS_SYNC(inode) && inode->i_dirt)
  348.             ext2_sync_inode (inode);
  349.         current->counter = 0;
  350.         schedule ();
  351.     }
  352.     inode->i_mtime = inode->i_ctime = CURRENT_TIME;
  353.     inode->i_dirt = 1;
  354. }
  355.