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/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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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                 mark_buffer_dirty(ind_bh, 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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                 mark_buffer_dirty(dind_bh, 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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                 mark_buffer_dirty(tind_bh, 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 250 {
 251         printk("ext_release not implemented\n");
 252 }

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