root/fs/minix/truncate.c

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

DEFINITIONS

This source file includes following definitions.
  1. V1_trunc_direct
  2. V1_trunc_indirect
  3. V1_trunc_dindirect
  4. V1_minix_truncate
  5. V2_trunc_direct
  6. V2_trunc_indirect
  7. V2_trunc_dindirect
  8. V2_trunc_tindirect
  9. V2_minix_truncate
  10. minix_truncate

   1 /*
   2  *  linux/fs/truncate.c
   3  *
   4  *  Copyright (C) 1991, 1992  Linus Torvalds
   5  *
   6  *  Copyright (C) 1996  Gertjan van Wingerde (gertjan@cs.vu.nl)
   7  *      Minix V2 fs support.
   8  */
   9 
  10 #include <linux/errno.h>
  11 #include <linux/sched.h>
  12 #include <linux/minix_fs.h>
  13 #include <linux/stat.h>
  14 #include <linux/fcntl.h>
  15 
  16 #define DIRECT_BLOCK            ((inode->i_size + 1023) >> 10)
  17 #define INDIRECT_BLOCK(offset)  (DIRECT_BLOCK-offset)
  18 #define DINDIRECT_BLOCK(offset) ((DIRECT_BLOCK-offset)>>9)
  19 #define TINDIRECT_BLOCK(offset) ((DIRECT_BLOCK-(offset))>>9)
  20 
  21 /*
  22  * Truncate has the most races in the whole filesystem: coding it is
  23  * a pain in the a**. Especially as I don't do any locking...
  24  *
  25  * The code may look a bit weird, but that's just because I've tried to
  26  * handle things like file-size changes in a somewhat graceful manner.
  27  * Anyway, truncating a file at the same time somebody else writes to it
  28  * is likely to result in pretty weird behaviour...
  29  *
  30  * The new code handles normal truncates (size = 0) as well as the more
  31  * general case (size = XXX). I hope.
  32  */
  33 
  34 /*
  35  * The functions for minix V1 fs truncation.
  36  */
  37 static int V1_trunc_direct(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
  38 {
  39         unsigned short * p;
  40         struct buffer_head * bh;
  41         int i, tmp;
  42         int retry = 0;
  43 
  44 repeat:
  45         for (i = DIRECT_BLOCK ; i < 7 ; i++) {
  46                 p = i + inode->u.minix_i.u.i1_data;
  47                 if (!(tmp = *p))
  48                         continue;
  49                 bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
  50                 if (i < DIRECT_BLOCK) {
  51                         brelse(bh);
  52                         goto repeat;
  53                 }
  54                 if ((bh && bh->b_count != 1) || tmp != *p) {
  55                         retry = 1;
  56                         brelse(bh);
  57                         continue;
  58                 }
  59                 *p = 0;
  60                 inode->i_dirt = 1;
  61                 if (bh) {
  62                         mark_buffer_clean(bh);
  63                         brelse(bh);
  64                 }
  65                 minix_free_block(inode->i_sb,tmp);
  66         }
  67         return retry;
  68 }
  69 
  70 static int V1_trunc_indirect(struct inode * inode, int offset, unsigned short * p)
     /* [previous][next][first][last][top][bottom][index][help] */
  71 {
  72         struct buffer_head * bh;
  73         int i, tmp;
  74         struct buffer_head * ind_bh;
  75         unsigned short * ind;
  76         int retry = 0;
  77 
  78         tmp = *p;
  79         if (!tmp)
  80                 return 0;
  81         ind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
  82         if (tmp != *p) {
  83                 brelse(ind_bh);
  84                 return 1;
  85         }
  86         if (!ind_bh) {
  87                 *p = 0;
  88                 return 0;
  89         }
  90 repeat:
  91         for (i = INDIRECT_BLOCK(offset) ; i < 512 ; i++) {
  92                 if (i < 0)
  93                         i = 0;
  94                 if (i < INDIRECT_BLOCK(offset))
  95                         goto repeat;
  96                 ind = i+(unsigned short *) ind_bh->b_data;
  97                 tmp = *ind;
  98                 if (!tmp)
  99                         continue;
 100                 bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
 101                 if (i < INDIRECT_BLOCK(offset)) {
 102                         brelse(bh);
 103                         goto repeat;
 104                 }
 105                 if ((bh && bh->b_count != 1) || tmp != *ind) {
 106                         retry = 1;
 107                         brelse(bh);
 108                         continue;
 109                 }
 110                 *ind = 0;
 111                 mark_buffer_dirty(ind_bh, 1);
 112                 brelse(bh);
 113                 minix_free_block(inode->i_sb,tmp);
 114         }
 115         ind = (unsigned short *) ind_bh->b_data;
 116         for (i = 0; i < 512; i++)
 117                 if (*(ind++))
 118                         break;
 119         if (i >= 512)
 120                 if (ind_bh->b_count != 1)
 121                         retry = 1;
 122                 else {
 123                         tmp = *p;
 124                         *p = 0;
 125                         minix_free_block(inode->i_sb,tmp);
 126                 }
 127         brelse(ind_bh);
 128         return retry;
 129 }
 130 
 131 static int V1_trunc_dindirect(struct inode * inode, int offset, unsigned short *p)
     /* [previous][next][first][last][top][bottom][index][help] */
 132 {
 133         int i, tmp;
 134         struct buffer_head * dind_bh;
 135         unsigned short * dind;
 136         int retry = 0;
 137 
 138         if (!(tmp = *p))
 139                 return 0;
 140         dind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
 141         if (tmp != *p) {
 142                 brelse(dind_bh);
 143                 return 1;
 144         }
 145         if (!dind_bh) {
 146                 *p = 0;
 147                 return 0;
 148         }
 149 repeat:
 150         for (i = DINDIRECT_BLOCK(offset) ; i < 512 ; i ++) {
 151                 if (i < 0)
 152                         i = 0;
 153                 if (i < DINDIRECT_BLOCK(offset))
 154                         goto repeat;
 155                 dind = i+(unsigned short *) dind_bh->b_data;
 156                 retry |= V1_trunc_indirect(inode,offset+(i<<9),dind);
 157                 mark_buffer_dirty(dind_bh, 1);
 158         }
 159         dind = (unsigned short *) dind_bh->b_data;
 160         for (i = 0; i < 512; i++)
 161                 if (*(dind++))
 162                         break;
 163         if (i >= 512)
 164                 if (dind_bh->b_count != 1)
 165                         retry = 1;
 166                 else {
 167                         tmp = *p;
 168                         *p = 0;
 169                         inode->i_dirt = 1;
 170                         minix_free_block(inode->i_sb,tmp);
 171                 }
 172         brelse(dind_bh);
 173         return retry;
 174 }
 175 
 176 void V1_minix_truncate(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 177 {
 178         int retry;
 179 
 180         if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
 181              S_ISLNK(inode->i_mode)))
 182                 return;
 183         while (1) {
 184                 retry = V1_trunc_direct(inode);
 185                 retry |= V1_trunc_indirect(inode, 7, inode->u.minix_i.u.i1_data + 7);
 186                 retry |= V1_trunc_dindirect(inode, 7+512, inode->u.minix_i.u.i1_data + 8);
 187                 if (!retry)
 188                         break;
 189                 current->counter = 0;
 190                 schedule();
 191         }
 192         inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 193         inode->i_dirt = 1;
 194 }
 195 
 196 /*
 197  * The functions for minix V2 fs truncation.
 198  */
 199 static int V2_trunc_direct(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 200 {
 201         unsigned long * p;
 202         struct buffer_head * bh;
 203         int i, tmp;
 204         int retry = 0;
 205 
 206 repeat:
 207         for (i = DIRECT_BLOCK ; i < 7 ; i++) {
 208                 p = (unsigned long *) inode->u.minix_i.u.i2_data + i;
 209                 if (!(tmp = *p))
 210                         continue;
 211                 bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
 212                 if (i < DIRECT_BLOCK) {
 213                         brelse(bh);
 214                         goto repeat;
 215                 }
 216                 if ((bh && bh->b_count != 1) || tmp != *p) {
 217                         retry = 1;
 218                         brelse(bh);
 219                         continue;
 220                 }
 221                 *p = 0;
 222                 inode->i_dirt = 1;
 223                 if (bh) {
 224                         mark_buffer_clean(bh);
 225                         brelse(bh);
 226                 }
 227                 minix_free_block(inode->i_sb,tmp);
 228         }
 229         return retry;
 230 }
 231 
 232 static int V2_trunc_indirect(struct inode * inode, int offset, unsigned long * p)
     /* [previous][next][first][last][top][bottom][index][help] */
 233 {
 234         struct buffer_head * bh;
 235         int i, tmp;
 236         struct buffer_head * ind_bh;
 237         unsigned long * ind;
 238         int retry = 0;
 239 
 240         tmp = *p;
 241         if (!tmp)
 242                 return 0;
 243         ind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
 244         if (tmp != *p) {
 245                 brelse(ind_bh);
 246                 return 1;
 247         }
 248         if (!ind_bh) {
 249                 *p = 0;
 250                 return 0;
 251         }
 252 repeat:
 253         for (i = INDIRECT_BLOCK(offset) ; i < 256 ; i++) {
 254                 if (i < 0)
 255                         i = 0;
 256                 if (i < INDIRECT_BLOCK(offset))
 257                         goto repeat;
 258                 ind = i+(unsigned long *) ind_bh->b_data;
 259                 tmp = *ind;
 260                 if (!tmp)
 261                         continue;
 262                 bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
 263                 if (i < INDIRECT_BLOCK(offset)) {
 264                         brelse(bh);
 265                         goto repeat;
 266                 }
 267                 if ((bh && bh->b_count != 1) || tmp != *ind) {
 268                         retry = 1;
 269                         brelse(bh);
 270                         continue;
 271                 }
 272                 *ind = 0;
 273                 mark_buffer_dirty(ind_bh, 1);
 274                 brelse(bh);
 275                 minix_free_block(inode->i_sb,tmp);
 276         }
 277         ind = (unsigned long *) ind_bh->b_data;
 278         for (i = 0; i < 256; i++)
 279                 if (*(ind++))
 280                         break;
 281         if (i >= 256)
 282                 if (ind_bh->b_count != 1)
 283                         retry = 1;
 284                 else {
 285                         tmp = *p;
 286                         *p = 0;
 287                         minix_free_block(inode->i_sb,tmp);
 288                 }
 289         brelse(ind_bh);
 290         return retry;
 291 }
 292 
 293 static int V2_trunc_dindirect(struct inode * inode, int offset, unsigned long *p)
     /* [previous][next][first][last][top][bottom][index][help] */
 294 {
 295         int i, tmp;
 296         struct buffer_head * dind_bh;
 297         unsigned long * dind;
 298         int retry = 0;
 299 
 300         if (!(tmp = *p))
 301                 return 0;
 302         dind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
 303         if (tmp != *p) {
 304                 brelse(dind_bh);
 305                 return 1;
 306         }
 307         if (!dind_bh) {
 308                 *p = 0;
 309                 return 0;
 310         }
 311 repeat:
 312         for (i = DINDIRECT_BLOCK(offset) ; i < 256 ; i ++) {
 313                 if (i < 0)
 314                         i = 0;
 315                 if (i < DINDIRECT_BLOCK(offset))
 316                         goto repeat;
 317                 dind = i+(unsigned long *) dind_bh->b_data;
 318                 retry |= V2_trunc_indirect(inode,offset+(i<<9),dind);
 319                 mark_buffer_dirty(dind_bh, 1);
 320         }
 321         dind = (unsigned long *) dind_bh->b_data;
 322         for (i = 0; i < 256; i++)
 323                 if (*(dind++))
 324                         break;
 325         if (i >= 256)
 326                 if (dind_bh->b_count != 1)
 327                         retry = 1;
 328                 else {
 329                         tmp = *p;
 330                         *p = 0;
 331                         inode->i_dirt = 1;
 332                         minix_free_block(inode->i_sb,tmp);
 333                 }
 334         brelse(dind_bh);
 335         return retry;
 336 }
 337 
 338 static int V2_trunc_tindirect(struct inode * inode, int offset, unsigned long * p)
     /* [previous][next][first][last][top][bottom][index][help] */
 339 {
 340         int i, tmp;
 341         struct buffer_head * tind_bh;
 342         unsigned long * tind;
 343         int retry = 0;
 344 
 345         if (!(tmp = *p))
 346                 return 0;
 347         tind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
 348         if (tmp != *p) {
 349                 brelse(tind_bh);
 350                 return 1;
 351         }
 352         if (!tind_bh) {
 353                 *p = 0;
 354                 return 0;
 355         }
 356 repeat:
 357         for (i = TINDIRECT_BLOCK(offset) ; i < 256 ; i ++) {
 358                 if (i < 0)
 359                         i = 0;
 360                 if (i < TINDIRECT_BLOCK(offset))
 361                         goto repeat;
 362                 tind = i+(unsigned long *) tind_bh->b_data;
 363                 retry |= V2_trunc_dindirect(inode,offset+(i<<9),tind);
 364                 mark_buffer_dirty(tind_bh, 1);
 365         }
 366         tind = (unsigned long *) tind_bh->b_data;
 367         for (i = 0; i < 256; i++)
 368                 if (*(tind++))
 369                         break;
 370         if (i >= 256)
 371                 if (tind_bh->b_count != 1)
 372                         retry = 1;
 373                 else {
 374                         tmp = *p;
 375                         *p = 0;
 376                         inode->i_dirt = 1;
 377                         minix_free_block(inode->i_sb,tmp);
 378                 }
 379         brelse(tind_bh);
 380         return retry;
 381 }
 382 
 383 static void V2_minix_truncate(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 384 {
 385         int retry;
 386 
 387         if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
 388              S_ISLNK(inode->i_mode)))
 389                 return;
 390         while (1) {
 391                 retry = V2_trunc_direct(inode);
 392                 retry |= V2_trunc_indirect(inode,7,
 393                         (unsigned long *) inode->u.minix_i.u.i2_data + 7);
 394                 retry |= V2_trunc_dindirect(inode, 7+256, 
 395                         (unsigned long *) inode->u.minix_i.u.i2_data + 8);
 396                 retry |= V2_trunc_tindirect(inode, 7+256+256*256, 
 397                         (unsigned long *) inode->u.minix_i.u.i2_data + 9);
 398                 if (!retry)
 399                         break;
 400                 current->counter = 0;
 401                 schedule();
 402         }
 403         inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 404         inode->i_dirt = 1;
 405 }
 406 
 407 /*
 408  * The function that is called for file truncation.
 409  */
 410 void minix_truncate(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 411 {
 412         if (INODE_VERSION(inode) == MINIX_V1)
 413                 V1_minix_truncate(inode);
 414         else
 415                 V2_minix_truncate(inode);
 416 }

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