root/fs/ext/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. ext_truncate
  6. ext_release

   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/tty.h>
  16 #include <linux/stat.h>
  17 #include <linux/fcntl.h>
  18 #include <linux/errno.h>
  19 
  20 /*
  21  * Truncate has the most races in the whole filesystem: coding it is
  22  * a pain in the a**. Especially as I don't do any locking...
  23  *
  24  * The code may look a bit weird, but that's just because I've tried to
  25  * handle things like file-size changes in a somewhat graceful manner.
  26  * Anyway, truncating a file at the same time somebody else writes to it
  27  * is likely to result in pretty weird behaviour...
  28  *
  29  * The new code handles normal truncates (size = 0) as well as the more
  30  * general case (size = XXX). I hope.
  31  */
  32 
  33 static int trunc_direct(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
  34 {
  35         int i;
  36         int result = 0;
  37 #define DIRECT_BLOCK ((inode->i_size + 1023) >> 10)
  38 
  39 repeat:
  40         for (i = DIRECT_BLOCK ; i < 9 ; i++) {
  41                 if (i < DIRECT_BLOCK)
  42                         goto repeat;
  43                 if (!inode->i_data[i])
  44                         continue;
  45                 result = 1;
  46                 if (ext_free_block(inode->i_dev,inode->i_data[i]))
  47                         inode->i_data[i] = 0;
  48         }
  49         return result;
  50 }
  51 
  52 static int trunc_indirect(struct inode * inode, int offset, unsigned long * p)
     /* [previous][next][first][last][top][bottom][index][help] */
  53 {
  54         int i;
  55         struct buffer_head * bh = NULL;
  56         unsigned long * ind;
  57         int result = 0;
  58 #define INDIRECT_BLOCK (DIRECT_BLOCK-offset)
  59 
  60         if (*p)
  61                 bh = bread(inode->i_dev, *p, BLOCK_SIZE);
  62         if (!bh)
  63                 return 0;
  64 repeat:
  65         for (i = INDIRECT_BLOCK ; i < 256 ; i++) {
  66                 if (i < 0)
  67                         i = 0;
  68                 if (i < INDIRECT_BLOCK)
  69                         goto repeat;
  70                 ind = i+(unsigned long *) bh->b_data;
  71                 if (!*ind)
  72                         continue;
  73                 result = 1;
  74                 if (ext_free_block(inode->i_dev,*ind))
  75                         *ind = 0;
  76         }
  77         ind = (unsigned long *) bh->b_data;
  78         for (i = 0; i < 256; i++)
  79                 if (*(ind++))
  80                         break;
  81         brelse(bh);
  82         if (i >= 256) {
  83                 result = 1;
  84                 if (ext_free_block(inode->i_dev,*p))
  85                         *p = 0;
  86         }
  87         return result;
  88 }
  89                 
  90 static int trunc_dindirect(struct inode * inode, int offset, unsigned long * p)
     /* [previous][next][first][last][top][bottom][index][help] */
  91 {
  92         int i;
  93         struct buffer_head * bh = NULL;
  94         unsigned long * dind;
  95         int result = 0;
  96 #define DINDIRECT_BLOCK ((DIRECT_BLOCK-offset)>>8)
  97 
  98         if (*p)
  99                 bh = bread(inode->i_dev, *p, BLOCK_SIZE);
 100         if (!bh)
 101                 return 0;
 102 repeat:
 103         for (i = DINDIRECT_BLOCK ; i < 256 ; i ++) {
 104                 if (i < 0)
 105                         i = 0;
 106                 if (i < DINDIRECT_BLOCK)
 107                         goto repeat;
 108                 dind = i+(unsigned long *) bh->b_data;
 109                 if (!*dind)
 110                         continue;
 111                 result |= trunc_indirect(inode,offset+(i<<8),dind);
 112         }
 113         dind = (unsigned long *) bh->b_data;
 114         for (i = 0; i < 256; i++)
 115                 if (*(dind++))
 116                         break;
 117         brelse(bh);
 118         if (i >= 256) {
 119                 result = 1;
 120                 if (ext_free_block(inode->i_dev,*p))
 121                         *p = 0;
 122         }
 123         return result;
 124 }
 125 
 126 static int trunc_tindirect(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 127 {
 128         int i;
 129         struct buffer_head * bh = NULL;
 130         unsigned long * tind;
 131         int result = 0;
 132 #define TINDIRECT_BLOCK ((DIRECT_BLOCK-(256*256+256+9))>>16)
 133 
 134         if (inode->i_data[11])
 135                 bh = bread(inode->i_dev, inode->i_data[11], BLOCK_SIZE);
 136         if (!bh)
 137                 return 0;
 138 repeat:
 139         for (i = TINDIRECT_BLOCK ; i < 256 ; i ++) {
 140                 if (i < 0)
 141                         i = 0;
 142                 if (i < TINDIRECT_BLOCK)
 143                         goto repeat;
 144                 tind = i+(unsigned long *) bh->b_data;
 145                 if (!*tind)
 146                         continue;
 147                 result |= trunc_dindirect(inode,9+256+256*256+(i<<16),tind);
 148         }
 149         tind = (unsigned long *) bh->b_data;
 150         for (i = 0; i < 256; i++)
 151                 if (*(tind++))
 152                         break;
 153         brelse(bh);
 154         if (i >= 256) {
 155                 result = 1;
 156                 if (ext_free_block(inode->i_dev,inode->i_data[11]))
 157                         inode->i_data[11] = 0;
 158         }
 159         return result;
 160 }
 161                 
 162 void ext_truncate(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 163 {
 164         int flag;
 165 
 166         if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
 167              S_ISLNK(inode->i_mode)))
 168                 return;
 169 /*      if (inode->i_data[7] & 0xffff0000)
 170                 printk("BAD! ext inode has 16 high bits set\n"); */
 171         while (1) {
 172                 flag = trunc_direct(inode);
 173                 flag |= trunc_indirect(inode,9,(unsigned long *)&inode->i_data[9]);
 174                 flag |= trunc_dindirect(inode,9+256,(unsigned long *)&inode->i_data[10]);
 175                 flag |= trunc_tindirect(inode);
 176                 if (!flag)
 177                         break;
 178                 current->counter = 0;
 179                 schedule();
 180         }
 181         inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 182         inode->i_dirt = 1;
 183 }
 184 
 185 /*
 186  * Called when a inode is released. Note that this is different
 187  * from ext_open: open gets called at every open, but release
 188  * gets called only when /all/ the files are closed.
 189  */
 190 void ext_release(struct inode * inode, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 191 {
 192         printk("ext_release not implemented\n");
 193 }

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