root/fs/ext2/truncate.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. trunc_direct
  2. trunc_indirect
  3. trunc_dindirect
  4. trunc_tindirect
  5. ext2_truncate

   1 /*
   2  *  linux/fs/ext2/truncate.c
   3  *
   4  * Copyright (C) 1992, 1993, 1994, 1995
   5  * Remy Card (card@masi.ibp.fr)
   6  * Laboratoire MASI - Institut Blaise Pascal
   7  * Universite Pierre et Marie Curie (Paris VI)
   8  *
   9  *  from
  10  *
  11  *  linux/fs/minix/truncate.c
  12  *
  13  *  Copyright (C) 1991, 1992  Linus Torvalds
  14  */
  15 
  16 /*
  17  * Real random numbers for secure rm added 94/02/18
  18  * Idea from Pierre del Perugia <delperug@gla.ecoledoc.ibp.fr>
  19  */
  20 
  21 #include <linux/errno.h>
  22 #include <linux/fs.h>
  23 #include <linux/ext2_fs.h>
  24 #include <linux/fcntl.h>
  25 #include <linux/sched.h>
  26 #include <linux/stat.h>
  27 #include <linux/locks.h>
  28 #include <linux/string.h>
  29 
  30 #if 0
  31 
  32 /*
  33  * Secure deletion currently doesn't work. It interacts very badly
  34  * with buffers shared with memory mappings, and for that reason
  35  * can't be done in the truncate() routines. It should instead be
  36  * done separately in "release()" before calling the truncate routines
  37  * that will release the actual file blocks.
  38  *
  39  *              Linus
  40  */
  41 static int ext2_secrm_seed = 152;       /* Random generator base */
  42 
  43 #define RANDOM_INT (ext2_secrm_seed = ext2_secrm_seed * 69069l +1)
  44 #endif
  45 
  46 /*
  47  * Truncate has the most races in the whole filesystem: coding it is
  48  * a pain in the a**. Especially as I don't do any locking...
  49  *
  50  * The code may look a bit weird, but that's just because I've tried to
  51  * handle things like file-size changes in a somewhat graceful manner.
  52  * Anyway, truncating a file at the same time somebody else writes to it
  53  * is likely to result in pretty weird behaviour...
  54  *
  55  * The new code handles normal truncates (size = 0) as well as the more
  56  * general case (size = XXX). I hope.
  57  */
  58 
  59 static int trunc_direct (struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
  60 {
  61         u32 * p;
  62         int i, tmp;
  63         struct buffer_head * bh;
  64         unsigned long block_to_free = 0;
  65         unsigned long free_count = 0;
  66         int retry = 0;
  67         int blocks = inode->i_sb->s_blocksize / 512;
  68 #define DIRECT_BLOCK ((inode->i_size + inode->i_sb->s_blocksize - 1) / \
  69                         inode->i_sb->s_blocksize)
  70         int direct_block = DIRECT_BLOCK;
  71 
  72 repeat:
  73         for (i = direct_block ; i < EXT2_NDIR_BLOCKS ; i++) {
  74                 p = inode->u.ext2_i.i_data + i;
  75                 tmp = *p;
  76                 if (!tmp)
  77                         continue;
  78                 bh = get_hash_table (inode->i_dev, tmp,
  79                                      inode->i_sb->s_blocksize);
  80                 if (i < direct_block) {
  81                         brelse (bh);
  82                         goto repeat;
  83                 }
  84                 if ((bh && bh->b_count != 1) || tmp != *p) {
  85                         retry = 1;
  86                         brelse (bh);
  87                         continue;
  88                 }
  89                 *p = 0;
  90                 inode->i_blocks -= blocks;
  91                 inode->i_dirt = 1;
  92                 bforget(bh);
  93                 if (free_count == 0) {
  94                         block_to_free = tmp;
  95                         free_count++;
  96                 } else if (free_count > 0 && block_to_free == tmp - free_count)
  97                         free_count++;
  98                 else {
  99                         ext2_free_blocks (inode->i_sb, block_to_free, free_count);
 100                         block_to_free = tmp;
 101                         free_count = 1;
 102                 }
 103 /*              ext2_free_blocks (inode->i_sb, tmp, 1); */
 104         }
 105         if (free_count > 0)
 106                 ext2_free_blocks (inode->i_sb, block_to_free, free_count);
 107         return retry;
 108 }
 109 
 110 static int trunc_indirect (struct inode * inode, int offset, u32 * p)
     /* [previous][next][first][last][top][bottom][index][help] */
 111 {
 112         int i, tmp;
 113         struct buffer_head * bh;
 114         struct buffer_head * ind_bh;
 115         u32 * ind;
 116         unsigned long block_to_free = 0;
 117         unsigned long free_count = 0;
 118         int retry = 0;
 119         int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
 120         int blocks = inode->i_sb->s_blocksize / 512;
 121 #define INDIRECT_BLOCK ((int)DIRECT_BLOCK - offset)
 122         int indirect_block = INDIRECT_BLOCK;
 123 
 124         tmp = *p;
 125         if (!tmp)
 126                 return 0;
 127         ind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
 128         if (tmp != *p) {
 129                 brelse (ind_bh);
 130                 return 1;
 131         }
 132         if (!ind_bh) {
 133                 *p = 0;
 134                 return 0;
 135         }
 136 repeat:
 137         for (i = indirect_block ; i < addr_per_block ; i++) {
 138                 if (i < 0)
 139                         i = 0;
 140                 if (i < indirect_block)
 141                         goto repeat;
 142                 ind = i + (u32 *) ind_bh->b_data;
 143                 tmp = *ind;
 144                 if (!tmp)
 145                         continue;
 146                 bh = get_hash_table (inode->i_dev, tmp,
 147                                      inode->i_sb->s_blocksize);
 148                 if (i < indirect_block) {
 149                         brelse (bh);
 150                         goto repeat;
 151                 }
 152                 if ((bh && bh->b_count != 1) || tmp != *ind) {
 153                         retry = 1;
 154                         brelse (bh);
 155                         continue;
 156                 }
 157                 *ind = 0;
 158                 mark_buffer_dirty(ind_bh, 1);
 159                 bforget(bh);
 160                 if (free_count == 0) {
 161                         block_to_free = tmp;
 162                         free_count++;
 163                 } else if (free_count > 0 && block_to_free == tmp - free_count)
 164                         free_count++;
 165                 else {
 166                         ext2_free_blocks (inode->i_sb, block_to_free, free_count);
 167                         block_to_free = tmp;
 168                         free_count = 1;
 169                 }
 170 /*              ext2_free_blocks (inode->i_sb, tmp, 1); */
 171                 inode->i_blocks -= blocks;
 172                 inode->i_dirt = 1;
 173         }
 174         if (free_count > 0)
 175                 ext2_free_blocks (inode->i_sb, block_to_free, free_count);
 176         ind = (u32 *) ind_bh->b_data;
 177         for (i = 0; i < addr_per_block; i++)
 178                 if (*(ind++))
 179                         break;
 180         if (i >= addr_per_block)
 181                 if (ind_bh->b_count != 1)
 182                         retry = 1;
 183                 else {
 184                         ind_bh->b_reuse = 1;
 185                         tmp = *p;
 186                         *p = 0;
 187                         inode->i_blocks -= blocks;
 188                         inode->i_dirt = 1;
 189                         ext2_free_blocks (inode->i_sb, tmp, 1);
 190                 }
 191         if (IS_SYNC(inode) && ind_bh->b_dirt) {
 192                 ll_rw_block (WRITE, 1, &ind_bh);
 193                 wait_on_buffer (ind_bh);
 194         }
 195         brelse (ind_bh);
 196         return retry;
 197 }
 198 
 199 static int trunc_dindirect (struct inode * inode, int offset,
     /* [previous][next][first][last][top][bottom][index][help] */
 200                             u32 * p)
 201 {
 202         int i, tmp;
 203         struct buffer_head * dind_bh;
 204         u32 * dind;
 205         int retry = 0;
 206         int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
 207         int blocks = inode->i_sb->s_blocksize / 512;
 208 #define DINDIRECT_BLOCK (((int)DIRECT_BLOCK - offset) / addr_per_block)
 209         int dindirect_block = DINDIRECT_BLOCK;
 210 
 211         tmp = *p;
 212         if (!tmp)
 213                 return 0;
 214         dind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
 215         if (tmp != *p) {
 216                 brelse (dind_bh);
 217                 return 1;
 218         }
 219         if (!dind_bh) {
 220                 *p = 0;
 221                 return 0;
 222         }
 223 repeat:
 224         for (i = dindirect_block ; i < addr_per_block ; i++) {
 225                 if (i < 0)
 226                         i = 0;
 227                 if (i < dindirect_block)
 228                         goto repeat;
 229                 dind = i + (u32 *) dind_bh->b_data;
 230                 tmp = *dind;
 231                 if (!tmp)
 232                         continue;
 233                 retry |= trunc_indirect (inode, offset + (i * addr_per_block),
 234                                           dind);
 235                 mark_buffer_dirty(dind_bh, 1);
 236         }
 237         dind = (u32 *) dind_bh->b_data;
 238         for (i = 0; i < addr_per_block; i++)
 239                 if (*(dind++))
 240                         break;
 241         if (i >= addr_per_block)
 242                 if (dind_bh->b_count != 1)
 243                         retry = 1;
 244                 else {
 245                         dind_bh->b_reuse = 1;
 246                         tmp = *p;
 247                         *p = 0;
 248                         inode->i_blocks -= blocks;
 249                         inode->i_dirt = 1;
 250                         ext2_free_blocks (inode->i_sb, tmp, 1);
 251                 }
 252         if (IS_SYNC(inode) && dind_bh->b_dirt) {
 253                 ll_rw_block (WRITE, 1, &dind_bh);
 254                 wait_on_buffer (dind_bh);
 255         }
 256         brelse (dind_bh);
 257         return retry;
 258 }
 259 
 260 static int trunc_tindirect (struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 261 {
 262         int i, tmp;
 263         struct buffer_head * tind_bh;
 264         u32 * tind, * p;
 265         int retry = 0;
 266         int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
 267         int blocks = inode->i_sb->s_blocksize / 512;
 268 #define TINDIRECT_BLOCK (((int)DIRECT_BLOCK - (addr_per_block * addr_per_block + \
 269                           addr_per_block + EXT2_NDIR_BLOCKS)) / \
 270                           (addr_per_block * addr_per_block))
 271         int tindirect_block = TINDIRECT_BLOCK;
 272 
 273         p = inode->u.ext2_i.i_data + EXT2_TIND_BLOCK;
 274         if (!(tmp = *p))
 275                 return 0;
 276         tind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
 277         if (tmp != *p) {
 278                 brelse (tind_bh);
 279                 return 1;
 280         }
 281         if (!tind_bh) {
 282                 *p = 0;
 283                 return 0;
 284         }
 285 repeat:
 286         for (i = tindirect_block ; i < addr_per_block ; i++) {
 287                 if (i < 0)
 288                         i = 0;
 289                 if (i < tindirect_block)
 290                         goto repeat;
 291                 tind = i + (u32 *) tind_bh->b_data;
 292                 retry |= trunc_dindirect(inode, EXT2_NDIR_BLOCKS +
 293                         addr_per_block + (i + 1) * addr_per_block * addr_per_block,
 294                         tind);
 295                 mark_buffer_dirty(tind_bh, 1);
 296         }
 297         tind = (u32 *) tind_bh->b_data;
 298         for (i = 0; i < addr_per_block; i++)
 299                 if (*(tind++))
 300                         break;
 301         if (i >= addr_per_block)
 302                 if (tind_bh->b_count != 1)
 303                         retry = 1;
 304                 else {
 305                         tind_bh->b_reuse = 1;
 306                         tmp = *p;
 307                         *p = 0;
 308                         inode->i_blocks -= blocks;
 309                         inode->i_dirt = 1;
 310                         ext2_free_blocks (inode->i_sb, tmp, 1);
 311                 }
 312         if (IS_SYNC(inode) && tind_bh->b_dirt) {
 313                 ll_rw_block (WRITE, 1, &tind_bh);
 314                 wait_on_buffer (tind_bh);
 315         }
 316         brelse (tind_bh);
 317         return retry;
 318 }
 319                 
 320 void ext2_truncate (struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 321 {
 322         int retry;
 323         struct buffer_head * bh;
 324         int err;
 325         int offset;
 326 
 327         if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
 328             S_ISLNK(inode->i_mode)))
 329                 return;
 330         if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
 331                 return;
 332         ext2_discard_prealloc(inode);
 333         while (1) {
 334                 down(&inode->i_sem);
 335                 retry = trunc_direct(inode);
 336                 retry |= trunc_indirect (inode, EXT2_IND_BLOCK,
 337                         (u32 *) &inode->u.ext2_i.i_data[EXT2_IND_BLOCK]);
 338                 retry |= trunc_dindirect (inode, EXT2_IND_BLOCK +
 339                         EXT2_ADDR_PER_BLOCK(inode->i_sb),
 340                         (u32 *) &inode->u.ext2_i.i_data[EXT2_DIND_BLOCK]);
 341                 retry |= trunc_tindirect (inode);
 342                 up(&inode->i_sem);
 343                 if (!retry)
 344                         break;
 345                 if (IS_SYNC(inode) && inode->i_dirt)
 346                         ext2_sync_inode (inode);
 347                 current->counter = 0;
 348                 schedule ();
 349         }
 350         /*
 351          * If the file is not being truncated to a block boundary, the
 352          * contents of the partial block following the end of the file must be
 353          * zeroed in case it ever becomes accessible again because of
 354          * subsequent file growth.
 355          */
 356         offset = inode->i_size & (inode->i_sb->s_blocksize - 1);
 357         if (offset) {
 358                 bh = ext2_bread (inode,
 359                                  inode->i_size >> EXT2_BLOCK_SIZE_BITS(inode->i_sb),
 360                                  0, &err);
 361                 if (bh) {
 362                         memset (bh->b_data + offset, 0,
 363                                 inode->i_sb->s_blocksize - offset);
 364                         mark_buffer_dirty (bh, 0);
 365                         brelse (bh);
 366                 }
 367         }
 368         inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 369         inode->i_dirt = 1;
 370 }

/* [previous][next][first][last][top][bottom][index][help] */