root/fs/minix/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. minix_truncate

   1 /*
   2  *  linux/fs/truncate.c
   3  *
   4  *  Copyright (C) 1991, 1992  Linus Torvalds
   5  */
   6 
   7 #include <linux/errno.h>
   8 #include <linux/sched.h>
   9 #include <linux/minix_fs.h>
  10 #include <linux/stat.h>
  11 #include <linux/fcntl.h>
  12 
  13 /*
  14  * Truncate has the most races in the whole filesystem: coding it is
  15  * a pain in the a**. Especially as I don't do any locking...
  16  *
  17  * The code may look a bit weird, but that's just because I've tried to
  18  * handle things like file-size changes in a somewhat graceful manner.
  19  * Anyway, truncating a file at the same time somebody else writes to it
  20  * is likely to result in pretty weird behaviour...
  21  *
  22  * The new code handles normal truncates (size = 0) as well as the more
  23  * general case (size = XXX). I hope.
  24  */
  25 
  26 static int trunc_direct(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
  27 {
  28         unsigned short * p;
  29         struct buffer_head * bh;
  30         int i, tmp;
  31         int retry = 0;
  32 #define DIRECT_BLOCK ((inode->i_size + 1023) >> 10)
  33 
  34 repeat:
  35         for (i = DIRECT_BLOCK ; i < 7 ; i++) {
  36                 p = i + inode->u.minix_i.i_data;
  37                 if (!(tmp = *p))
  38                         continue;
  39                 bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
  40                 if (i < DIRECT_BLOCK) {
  41                         brelse(bh);
  42                         goto repeat;
  43                 }
  44                 if ((bh && bh->b_count != 1) || tmp != *p) {
  45                         retry = 1;
  46                         brelse(bh);
  47                         continue;
  48                 }
  49                 *p = 0;
  50                 inode->i_dirt = 1;
  51                 if (bh) {
  52                         mark_buffer_clean(bh);
  53                         brelse(bh);
  54                 }
  55                 minix_free_block(inode->i_sb,tmp);
  56         }
  57         return retry;
  58 }
  59 
  60 static int trunc_indirect(struct inode * inode, int offset, unsigned short * p)
     /* [previous][next][first][last][top][bottom][index][help] */
  61 {
  62         struct buffer_head * bh;
  63         int i, tmp;
  64         struct buffer_head * ind_bh;
  65         unsigned short * ind;
  66         int retry = 0;
  67 #define INDIRECT_BLOCK (DIRECT_BLOCK-offset)
  68 
  69         tmp = *p;
  70         if (!tmp)
  71                 return 0;
  72         ind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
  73         if (tmp != *p) {
  74                 brelse(ind_bh);
  75                 return 1;
  76         }
  77         if (!ind_bh) {
  78                 *p = 0;
  79                 return 0;
  80         }
  81 repeat:
  82         for (i = INDIRECT_BLOCK ; i < 512 ; i++) {
  83                 if (i < 0)
  84                         i = 0;
  85                 if (i < INDIRECT_BLOCK)
  86                         goto repeat;
  87                 ind = i+(unsigned short *) ind_bh->b_data;
  88                 tmp = *ind;
  89                 if (!tmp)
  90                         continue;
  91                 bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
  92                 if (i < INDIRECT_BLOCK) {
  93                         brelse(bh);
  94                         goto repeat;
  95                 }
  96                 if ((bh && bh->b_count != 1) || tmp != *ind) {
  97                         retry = 1;
  98                         brelse(bh);
  99                         continue;
 100                 }
 101                 *ind = 0;
 102                 mark_buffer_dirty(ind_bh, 1);
 103                 brelse(bh);
 104                 minix_free_block(inode->i_sb,tmp);
 105         }
 106         ind = (unsigned short *) ind_bh->b_data;
 107         for (i = 0; i < 512; i++)
 108                 if (*(ind++))
 109                         break;
 110         if (i >= 512)
 111                 if (ind_bh->b_count != 1)
 112                         retry = 1;
 113                 else {
 114                         tmp = *p;
 115                         *p = 0;
 116                         minix_free_block(inode->i_sb,tmp);
 117                 }
 118         brelse(ind_bh);
 119         return retry;
 120 }
 121                 
 122 static int trunc_dindirect(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 123 {
 124         int i, tmp;
 125         struct buffer_head * dind_bh;
 126         unsigned short * dind, * p;
 127         int retry = 0;
 128 #define DINDIRECT_BLOCK ((DIRECT_BLOCK-(512+7))>>9)
 129 
 130         p = 8 + inode->u.minix_i.i_data;
 131         if (!(tmp = *p))
 132                 return 0;
 133         dind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
 134         if (tmp != *p) {
 135                 brelse(dind_bh);
 136                 return 1;
 137         }
 138         if (!dind_bh) {
 139                 *p = 0;
 140                 return 0;
 141         }
 142 repeat:
 143         for (i = DINDIRECT_BLOCK ; i < 512 ; i ++) {
 144                 if (i < 0)
 145                         i = 0;
 146                 if (i < DINDIRECT_BLOCK)
 147                         goto repeat;
 148                 dind = i+(unsigned short *) dind_bh->b_data;
 149                 retry |= trunc_indirect(inode,7+512+(i<<9),dind);
 150                 mark_buffer_dirty(dind_bh, 1);
 151         }
 152         dind = (unsigned short *) dind_bh->b_data;
 153         for (i = 0; i < 512; i++)
 154                 if (*(dind++))
 155                         break;
 156         if (i >= 512)
 157                 if (dind_bh->b_count != 1)
 158                         retry = 1;
 159                 else {
 160                         tmp = *p;
 161                         *p = 0;
 162                         inode->i_dirt = 1;
 163                         minix_free_block(inode->i_sb,tmp);
 164                 }
 165         brelse(dind_bh);
 166         return retry;
 167 }
 168                 
 169 void minix_truncate(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 170 {
 171         int retry;
 172 
 173         if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
 174              S_ISLNK(inode->i_mode)))
 175                 return;
 176         while (1) {
 177                 retry = trunc_direct(inode);
 178                 retry |= trunc_indirect(inode,7,inode->u.minix_i.i_data+7);
 179                 retry |= trunc_dindirect(inode);
 180                 if (!retry)
 181                         break;
 182                 current->counter = 0;
 183                 schedule();
 184         }
 185         inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 186         inode->i_dirt = 1;
 187 }

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