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                 brelse(bh);
  56                 minix_free_block(inode->i_sb,tmp);
  57         }
  58         return retry;
  59 }
  60 
  61 static int trunc_indirect(struct inode * inode, int offset, unsigned short * p)
     /* [previous][next][first][last][top][bottom][index][help] */
  62 {
  63         struct buffer_head * bh;
  64         int i, tmp;
  65         struct buffer_head * ind_bh;
  66         unsigned short * ind;
  67         int retry = 0;
  68 #define INDIRECT_BLOCK (DIRECT_BLOCK-offset)
  69 
  70         tmp = *p;
  71         if (!tmp)
  72                 return 0;
  73         ind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
  74         if (tmp != *p) {
  75                 brelse(ind_bh);
  76                 return 1;
  77         }
  78         if (!ind_bh) {
  79                 *p = 0;
  80                 return 0;
  81         }
  82 repeat:
  83         for (i = INDIRECT_BLOCK ; i < 512 ; i++) {
  84                 if (i < 0)
  85                         i = 0;
  86                 if (i < INDIRECT_BLOCK)
  87                         goto repeat;
  88                 ind = i+(unsigned short *) ind_bh->b_data;
  89                 tmp = *ind;
  90                 if (!tmp)
  91                         continue;
  92                 bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
  93                 if (i < INDIRECT_BLOCK) {
  94                         brelse(bh);
  95                         goto repeat;
  96                 }
  97                 if ((bh && bh->b_count != 1) || tmp != *ind) {
  98                         retry = 1;
  99                         brelse(bh);
 100                         continue;
 101                 }
 102                 *ind = 0;
 103                 mark_buffer_dirty(ind_bh, 1);
 104                 brelse(bh);
 105                 minix_free_block(inode->i_sb,tmp);
 106         }
 107         ind = (unsigned short *) ind_bh->b_data;
 108         for (i = 0; i < 512; i++)
 109                 if (*(ind++))
 110                         break;
 111         if (i >= 512)
 112                 if (ind_bh->b_count != 1)
 113                         retry = 1;
 114                 else {
 115                         tmp = *p;
 116                         *p = 0;
 117                         minix_free_block(inode->i_sb,tmp);
 118                 }
 119         brelse(ind_bh);
 120         return retry;
 121 }
 122                 
 123 static int trunc_dindirect(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 124 {
 125         int i, tmp;
 126         struct buffer_head * dind_bh;
 127         unsigned short * dind, * p;
 128         int retry = 0;
 129 #define DINDIRECT_BLOCK ((DIRECT_BLOCK-(512+7))>>9)
 130 
 131         p = 8 + inode->u.minix_i.i_data;
 132         if (!(tmp = *p))
 133                 return 0;
 134         dind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
 135         if (tmp != *p) {
 136                 brelse(dind_bh);
 137                 return 1;
 138         }
 139         if (!dind_bh) {
 140                 *p = 0;
 141                 return 0;
 142         }
 143 repeat:
 144         for (i = DINDIRECT_BLOCK ; i < 512 ; i ++) {
 145                 if (i < 0)
 146                         i = 0;
 147                 if (i < DINDIRECT_BLOCK)
 148                         goto repeat;
 149                 dind = i+(unsigned short *) dind_bh->b_data;
 150                 retry |= trunc_indirect(inode,7+512+(i<<9),dind);
 151                 mark_buffer_dirty(dind_bh, 1);
 152         }
 153         dind = (unsigned short *) dind_bh->b_data;
 154         for (i = 0; i < 512; i++)
 155                 if (*(dind++))
 156                         break;
 157         if (i >= 512)
 158                 if (dind_bh->b_count != 1)
 159                         retry = 1;
 160                 else {
 161                         tmp = *p;
 162                         *p = 0;
 163                         inode->i_dirt = 1;
 164                         minix_free_block(inode->i_sb,tmp);
 165                 }
 166         brelse(dind_bh);
 167         return retry;
 168 }
 169                 
 170 void minix_truncate(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 171 {
 172         int retry;
 173 
 174         if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
 175              S_ISLNK(inode->i_mode)))
 176                 return;
 177         while (1) {
 178                 retry = trunc_direct(inode);
 179                 retry |= trunc_indirect(inode,7,inode->u.minix_i.i_data+7);
 180                 retry |= trunc_dindirect(inode);
 181                 if (!retry)
 182                         break;
 183                 current->counter = 0;
 184                 schedule();
 185         }
 186         inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 187         inode->i_dirt = 1;
 188 }

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