|
|
1.1 root 1: /*
2: * linux/fs/ext/truncate.c
3: *
1.1.1.2 root 4: * Copyright (C) 1992 Remy Card ([email protected])
1.1 root 5: *
6: * from
7: *
8: * linux/fs/minix/truncate.c
9: *
1.1.1.2 root 10: * Copyright (C) 1991, 1992 Linus Torvalds
1.1 root 11: */
12:
13: #include <linux/sched.h>
14: #include <linux/ext_fs.h>
15: #include <linux/tty.h>
16: #include <linux/stat.h>
17: #include <linux/fcntl.h>
1.1.1.2 root 18: #include <linux/errno.h>
1.1 root 19:
20: /*
21: * Truncate has the most races in the whole filesystem: coding it is
22: * a pain in the a**. Especially as I don't do any locking...
23: *
24: * The code may look a bit weird, but that's just because I've tried to
25: * handle things like file-size changes in a somewhat graceful manner.
26: * Anyway, truncating a file at the same time somebody else writes to it
27: * is likely to result in pretty weird behaviour...
28: *
29: * The new code handles normal truncates (size = 0) as well as the more
30: * general case (size = XXX). I hope.
31: */
32:
33: static int trunc_direct(struct inode * inode)
34: {
1.1.1.3 ! root 35: int i, tmp;
! 36: unsigned long * p;
! 37: struct buffer_head * bh;
! 38: int retry = 0;
1.1 root 39: #define DIRECT_BLOCK ((inode->i_size + 1023) >> 10)
40:
41: repeat:
42: for (i = DIRECT_BLOCK ; i < 9 ; i++) {
1.1.1.3 ! root 43: p = inode->u.ext_i.i_data+i;
! 44: if (!(tmp = *p))
! 45: continue;
! 46: bh = getblk(inode->i_dev,tmp,BLOCK_SIZE);
! 47: if (i < DIRECT_BLOCK) {
! 48: brelse(bh);
1.1 root 49: goto repeat;
1.1.1.3 ! root 50: }
! 51: if ((bh && bh->b_count != 1) || tmp != *p) {
! 52: retry = 1;
! 53: brelse(bh);
1.1 root 54: continue;
1.1.1.3 ! root 55: }
! 56: *p = 0;
! 57: inode->i_dirt = 1;
! 58: brelse(bh);
! 59: ext_free_block(inode->i_dev,tmp);
1.1 root 60: }
1.1.1.3 ! root 61: return retry;
1.1 root 62: }
63:
64: static int trunc_indirect(struct inode * inode, int offset, unsigned long * p)
65: {
1.1.1.3 ! root 66: int i, tmp;
! 67: struct buffer_head * bh;
! 68: struct buffer_head * ind_bh;
1.1 root 69: unsigned long * ind;
1.1.1.3 ! root 70: int retry = 0;
1.1 root 71: #define INDIRECT_BLOCK (DIRECT_BLOCK-offset)
72:
1.1.1.3 ! root 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;
1.1 root 83: return 0;
1.1.1.3 ! root 84: }
1.1 root 85: repeat:
86: for (i = INDIRECT_BLOCK ; i < 256 ; i++) {
87: if (i < 0)
88: i = 0;
89: if (i < INDIRECT_BLOCK)
90: goto repeat;
1.1.1.3 ! root 91: ind = i+(unsigned long *) ind_bh->b_data;
! 92: tmp = *ind;
! 93: if (!tmp)
! 94: continue;
! 95: bh = getblk(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);
1.1 root 103: continue;
1.1.1.3 ! root 104: }
! 105: *ind = 0;
! 106: ind_bh->b_dirt = 1;
! 107: brelse(bh);
! 108: ext_free_block(inode->i_dev,tmp);
1.1 root 109: }
1.1.1.3 ! root 110: ind = (unsigned long *) ind_bh->b_data;
1.1 root 111: for (i = 0; i < 256; i++)
112: if (*(ind++))
113: break;
1.1.1.3 ! root 114: if (i >= 256)
! 115: if (ind_bh->b_count != 1)
! 116: retry = 1;
! 117: else {
! 118: tmp = *p;
1.1 root 119: *p = 0;
1.1.1.3 ! root 120: inode->i_dirt = 1;
! 121: ext_free_block(inode->i_dev,tmp);
! 122: }
! 123: brelse(ind_bh);
! 124: return retry;
1.1 root 125: }
1.1.1.3 ! root 126:
1.1.1.2 root 127: static int trunc_dindirect(struct inode * inode, int offset, unsigned long * p)
1.1 root 128: {
1.1.1.3 ! root 129: int i,tmp;
! 130: struct buffer_head * dind_bh;
1.1 root 131: unsigned long * dind;
1.1.1.3 ! root 132: int retry = 0;
1.1.1.2 root 133: #define DINDIRECT_BLOCK ((DIRECT_BLOCK-offset)>>8)
1.1 root 134:
1.1.1.3 ! root 135: tmp = *p;
! 136: if (!tmp)
! 137: return 0;
! 138: dind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
! 139: if (tmp != *p) {
! 140: brelse(dind_bh);
! 141: return 1;
! 142: }
! 143: if (!dind_bh) {
! 144: *p = 0;
1.1 root 145: return 0;
1.1.1.3 ! root 146: }
1.1 root 147: repeat:
148: for (i = DINDIRECT_BLOCK ; i < 256 ; i ++) {
149: if (i < 0)
150: i = 0;
151: if (i < DINDIRECT_BLOCK)
152: goto repeat;
1.1.1.3 ! root 153: dind = i+(unsigned long *) dind_bh->b_data;
! 154: tmp = *dind;
! 155: if (!tmp)
1.1 root 156: continue;
1.1.1.3 ! root 157: retry |= trunc_indirect(inode,offset+(i<<8),dind);
! 158: dind_bh->b_dirt = 1;
1.1 root 159: }
1.1.1.3 ! root 160: dind = (unsigned long *) dind_bh->b_data;
1.1 root 161: for (i = 0; i < 256; i++)
162: if (*(dind++))
163: break;
1.1.1.3 ! root 164: if (i >= 256)
! 165: if (dind_bh->b_count != 1)
! 166: retry = 1;
! 167: else {
! 168: tmp = *p;
1.1.1.2 root 169: *p = 0;
1.1.1.3 ! root 170: inode->i_dirt = 1;
! 171: ext_free_block(inode->i_dev,tmp);
! 172: }
! 173: brelse(dind_bh);
! 174: return retry;
1.1.1.2 root 175: }
176:
177: static int trunc_tindirect(struct inode * inode)
178: {
1.1.1.3 ! root 179: int i,tmp;
! 180: struct buffer_head * tind_bh;
! 181: unsigned long * tind, * p;
! 182: int retry = 0;
1.1.1.2 root 183: #define TINDIRECT_BLOCK ((DIRECT_BLOCK-(256*256+256+9))>>16)
184:
1.1.1.3 ! root 185: p = inode->u.ext_i.i_data+11;
! 186: if (!(tmp = *p))
1.1.1.2 root 187: return 0;
1.1.1.3 ! root 188: tind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
! 189: if (tmp != *p) {
! 190: brelse(tind_bh);
! 191: return 1;
! 192: }
! 193: if (!tind_bh) {
! 194: *p = 0;
! 195: return 0;
! 196: }
1.1.1.2 root 197: repeat:
198: for (i = TINDIRECT_BLOCK ; i < 256 ; i ++) {
199: if (i < 0)
200: i = 0;
201: if (i < TINDIRECT_BLOCK)
202: goto repeat;
1.1.1.3 ! root 203: tind = i+(unsigned long *) tind_bh->b_data;
! 204: retry |= trunc_dindirect(inode,9+256+256*256+(i<<16),tind);
! 205: tind_bh->b_dirt = 1;
1.1.1.2 root 206: }
1.1.1.3 ! root 207: tind = (unsigned long *) tind_bh->b_data;
1.1.1.2 root 208: for (i = 0; i < 256; i++)
209: if (*(tind++))
210: break;
1.1.1.3 ! root 211: if (i >= 256)
! 212: if (tind_bh->b_count != 1)
! 213: retry = 1;
! 214: else {
! 215: tmp = *p;
! 216: *p = 0;
! 217: inode->i_dirt = 1;
! 218: ext_free_block(inode->i_dev,tmp);
! 219: }
! 220: brelse(tind_bh);
! 221: return retry;
1.1 root 222: }
1.1.1.3 ! root 223:
1.1 root 224: void ext_truncate(struct inode * inode)
225: {
1.1.1.3 ! root 226: int retry;
1.1 root 227:
228: if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
229: S_ISLNK(inode->i_mode)))
230: return;
231: while (1) {
1.1.1.3 ! root 232: retry = trunc_direct(inode);
! 233: retry |= trunc_indirect(inode,9,inode->u.ext_i.i_data+9);
! 234: retry |= trunc_dindirect(inode,9+256,inode->u.ext_i.i_data+10);
! 235: retry |= trunc_tindirect(inode);
! 236: if (!retry)
1.1 root 237: break;
238: current->counter = 0;
239: schedule();
240: }
241: inode->i_mtime = inode->i_ctime = CURRENT_TIME;
242: inode->i_dirt = 1;
243: }
244:
245: /*
246: * Called when a inode is released. Note that this is different
247: * from ext_open: open gets called at every open, but release
248: * gets called only when /all/ the files are closed.
249: */
250: void ext_release(struct inode * inode, struct file * filp)
251: {
252: printk("ext_release not implemented\n");
253: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.