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

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