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, tmp;
  36         unsigned long * p;
  37         struct buffer_head * bh;
  38         int retry = 0;
  39 #define DIRECT_BLOCK ((inode->i_size + 1023) >> 10)
  40 
  41 repeat:
  42         for (i = DIRECT_BLOCK ; i < 9 ; i++) {
  43                 p = inode->u.ext_i.i_data+i;
  44                 if (!(tmp = *p))
  45                         continue;
  46                 bh = getblk(inode->i_dev,tmp,BLOCK_SIZE);
  47                 if (i < DIRECT_BLOCK) {
  48                         brelse(bh);
  49                         goto repeat;
  50                 }
  51                 if ((bh && bh->b_count != 1) || tmp != *p) {
  52                         retry = 1;
  53                         brelse(bh);
  54                         continue;
  55                 }
  56                 *p = 0;
  57                 inode->i_dirt = 1;
  58                 brelse(bh);
  59                 ext_free_block(inode->i_dev,tmp);
  60         }
  61         return retry;
  62 }
  63 
  64 static int trunc_indirect(struct inode * inode, int offset, unsigned long * p)
     /* [previous][next][first][last][top][bottom][index][help] */
  65 {
  66         int i, tmp;
  67         struct buffer_head * bh;
  68         struct buffer_head * ind_bh;
  69         unsigned long * ind;
  70         int retry = 0;
  71 #define INDIRECT_BLOCK (DIRECT_BLOCK-offset)
  72 
  73         tmp = *p;
  74         if (!tmp)
  75                 return 0;
  76         ind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
  77         if (tmp != *p) {
  78                 brelse(ind_bh);
  79                 return 1;
  80         }
  81         if (!ind_bh) {
  82                 *p = 0;
  83                 return 0;
  84         }
  85 repeat:
  86         for (i = INDIRECT_BLOCK ; i < 256 ; i++) {
  87                 if (i < 0)
  88                         i = 0;
  89                 if (i < INDIRECT_BLOCK)
  90                         goto repeat;
  91                 ind = i+(unsigned long *) ind_bh->b_data;
  92                 tmp = *ind;
  93                 if (!tmp)
  94                         continue;
  95                 bh = getblk(inode->i_dev,tmp,BLOCK_SIZE);
  96                 if (i < INDIRECT_BLOCK) {
  97                         brelse(bh);
  98                         goto repeat;
  99                 }
 100                 if ((bh && bh->b_count != 1) || tmp != *ind) {
 101                         retry = 1;
 102                         brelse(bh);
 103                         continue;
 104                 }
 105                 *ind = 0;
 106                 ind_bh->b_dirt = 1;
 107                 brelse(bh);
 108                 ext_free_block(inode->i_dev,tmp);
 109         }
 110         ind = (unsigned long *) ind_bh->b_data;
 111         for (i = 0; i < 256; i++)
 112                 if (*(ind++))
 113                         break;
 114         if (i >= 256)
 115                 if (ind_bh->b_count != 1)
 116                         retry = 1;
 117                 else {
 118                         tmp = *p;
 119                         *p = 0;
 120                         inode->i_dirt = 1;
 121                         ext_free_block(inode->i_dev,tmp);
 122                 }
 123         brelse(ind_bh);
 124         return retry;
 125 }
 126 
 127 static int trunc_dindirect(struct inode * inode, int offset, unsigned long * p)
     /* [previous][next][first][last][top][bottom][index][help] */
 128 {
 129         int i,tmp;
 130         struct buffer_head * dind_bh;
 131         unsigned long * dind;
 132         int retry = 0;
 133 #define DINDIRECT_BLOCK ((DIRECT_BLOCK-offset)>>8)
 134 
 135         tmp = *p;
 136         if (!tmp)
 137                 return 0;
 138         dind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
 139         if (tmp != *p) {
 140                 brelse(dind_bh);
 141                 return 1;
 142         }
 143         if (!dind_bh) {
 144                 *p = 0;
 145                 return 0;
 146         }
 147 repeat:
 148         for (i = DINDIRECT_BLOCK ; i < 256 ; i ++) {
 149                 if (i < 0)
 150                         i = 0;
 151                 if (i < DINDIRECT_BLOCK)
 152                         goto repeat;
 153                 dind = i+(unsigned long *) dind_bh->b_data;
 154                 tmp = *dind;
 155                 if (!tmp)
 156                         continue;
 157                 retry |= trunc_indirect(inode,offset+(i<<8),dind);
 158                 dind_bh->b_dirt = 1;
 159         }
 160         dind = (unsigned long *) dind_bh->b_data;
 161         for (i = 0; i < 256; i++)
 162                 if (*(dind++))
 163                         break;
 164         if (i >= 256)
 165                 if (dind_bh->b_count != 1)
 166                         retry = 1;
 167                 else {
 168                         tmp = *p;
 169                         *p = 0;
 170                         inode->i_dirt = 1;
 171                         ext_free_block(inode->i_dev,tmp);
 172                 }
 173         brelse(dind_bh);
 174         return retry;
 175 }
 176 
 177 static int trunc_tindirect(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 178 {
 179         int i,tmp;
 180         struct buffer_head * tind_bh;
 181         unsigned long * tind, * p;
 182         int retry = 0;
 183 #define TINDIRECT_BLOCK ((DIRECT_BLOCK-(256*256+256+9))>>16)
 184 
 185         p = inode->u.ext_i.i_data+11;
 186         if (!(tmp = *p))
 187                 return 0;
 188         tind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
 189         if (tmp != *p) {
 190                 brelse(tind_bh);
 191                 return 1;
 192         }
 193         if (!tind_bh) {
 194                 *p = 0;
 195                 return 0;
 196         }
 197 repeat:
 198         for (i = TINDIRECT_BLOCK ; i < 256 ; i ++) {
 199                 if (i < 0)
 200                         i = 0;
 201                 if (i < TINDIRECT_BLOCK)
 202                         goto repeat;
 203                 tind = i+(unsigned long *) tind_bh->b_data;
 204                 retry |= trunc_dindirect(inode,9+256+256*256+(i<<16),tind);
 205                 tind_bh->b_dirt = 1;
 206         }
 207         tind = (unsigned long *) tind_bh->b_data;
 208         for (i = 0; i < 256; i++)
 209                 if (*(tind++))
 210                         break;
 211         if (i >= 256)
 212                 if (tind_bh->b_count != 1)
 213                         retry = 1;
 214                 else {
 215                         tmp = *p;
 216                         *p = 0;
 217                         inode->i_dirt = 1;
 218                         ext_free_block(inode->i_dev,tmp);
 219                 }
 220         brelse(tind_bh);
 221         return retry;
 222 }
 223 
 224 void ext_truncate(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 225 {
 226         int retry;
 227 
 228         if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
 229              S_ISLNK(inode->i_mode)))
 230                 return;
 231         while (1) {
 232                 retry = trunc_direct(inode);
 233                 retry |= trunc_indirect(inode,9,inode->u.ext_i.i_data+9);
 234                 retry |= trunc_dindirect(inode,9+256,inode->u.ext_i.i_data+10);
 235                 retry |= trunc_tindirect(inode);
 236                 if (!retry)
 237                         break;
 238                 current->counter = 0;
 239                 schedule();
 240         }
 241         inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 242         inode->i_dirt = 1;
 243 }
 244 
 245 /*
 246  * Called when a inode is released. Note that this is different
 247  * from ext_open: open gets called at every open, but release
 248  * gets called only when /all/ the files are closed.
 249  */
 250 void ext_release(struct inode * inode, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 251 {
 252         printk("ext_release not implemented\n");
 253 }

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