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

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