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

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