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

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