root/fs/xiafs/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. xiafs_truncate

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

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