|
|
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: {
35: int i;
36: int result = 0;
37: #define DIRECT_BLOCK ((inode->i_size + 1023) >> 10)
38:
39: repeat:
40: for (i = DIRECT_BLOCK ; i < 9 ; i++) {
41: if (i < DIRECT_BLOCK)
42: goto repeat;
43: if (!inode->i_data[i])
44: continue;
45: result = 1;
46: if (ext_free_block(inode->i_dev,inode->i_data[i]))
47: inode->i_data[i] = 0;
48: }
49: return result;
50: }
51:
52: static int trunc_indirect(struct inode * inode, int offset, unsigned long * p)
53: {
54: int i;
55: struct buffer_head * bh = NULL;
56: unsigned long * ind;
57: int result = 0;
58: #define INDIRECT_BLOCK (DIRECT_BLOCK-offset)
59:
60: if (*p)
1.1.1.2 ! root 61: bh = bread(inode->i_dev, *p, BLOCK_SIZE);
1.1 root 62: if (!bh)
63: return 0;
64: repeat:
65: for (i = INDIRECT_BLOCK ; i < 256 ; i++) {
66: if (i < 0)
67: i = 0;
68: if (i < INDIRECT_BLOCK)
69: goto repeat;
70: ind = i+(unsigned long *) bh->b_data;
71: if (!*ind)
72: continue;
73: result = 1;
74: if (ext_free_block(inode->i_dev,*ind))
75: *ind = 0;
76: }
77: ind = (unsigned long *) bh->b_data;
78: for (i = 0; i < 256; i++)
79: if (*(ind++))
80: break;
81: brelse(bh);
82: if (i >= 256) {
83: result = 1;
84: if (ext_free_block(inode->i_dev,*p))
85: *p = 0;
86: }
87: return result;
88: }
89:
1.1.1.2 ! root 90: static int trunc_dindirect(struct inode * inode, int offset, unsigned long * p)
1.1 root 91: {
92: int i;
93: struct buffer_head * bh = NULL;
94: unsigned long * dind;
95: int result = 0;
1.1.1.2 ! root 96: #define DINDIRECT_BLOCK ((DIRECT_BLOCK-offset)>>8)
1.1 root 97:
1.1.1.2 ! root 98: if (*p)
! 99: bh = bread(inode->i_dev, *p, BLOCK_SIZE);
1.1 root 100: if (!bh)
101: return 0;
102: repeat:
103: for (i = DINDIRECT_BLOCK ; i < 256 ; i ++) {
104: if (i < 0)
105: i = 0;
106: if (i < DINDIRECT_BLOCK)
107: goto repeat;
108: dind = i+(unsigned long *) bh->b_data;
109: if (!*dind)
110: continue;
1.1.1.2 ! root 111: result |= trunc_indirect(inode,offset+(i<<8),dind);
1.1 root 112: }
113: dind = (unsigned long *) bh->b_data;
114: for (i = 0; i < 256; i++)
115: if (*(dind++))
116: break;
117: brelse(bh);
118: if (i >= 256) {
119: result = 1;
1.1.1.2 ! root 120: if (ext_free_block(inode->i_dev,*p))
! 121: *p = 0;
! 122: }
! 123: return result;
! 124: }
! 125:
! 126: static int trunc_tindirect(struct inode * inode)
! 127: {
! 128: int i;
! 129: struct buffer_head * bh = NULL;
! 130: unsigned long * tind;
! 131: int result = 0;
! 132: #define TINDIRECT_BLOCK ((DIRECT_BLOCK-(256*256+256+9))>>16)
! 133:
! 134: if (inode->i_data[11])
! 135: bh = bread(inode->i_dev, inode->i_data[11], BLOCK_SIZE);
! 136: if (!bh)
! 137: return 0;
! 138: repeat:
! 139: for (i = TINDIRECT_BLOCK ; i < 256 ; i ++) {
! 140: if (i < 0)
! 141: i = 0;
! 142: if (i < TINDIRECT_BLOCK)
! 143: goto repeat;
! 144: tind = i+(unsigned long *) bh->b_data;
! 145: if (!*tind)
! 146: continue;
! 147: result |= trunc_dindirect(inode,9+256+256*256+(i<<16),tind);
! 148: }
! 149: tind = (unsigned long *) bh->b_data;
! 150: for (i = 0; i < 256; i++)
! 151: if (*(tind++))
! 152: break;
! 153: brelse(bh);
! 154: if (i >= 256) {
! 155: result = 1;
! 156: if (ext_free_block(inode->i_dev,inode->i_data[11]))
! 157: inode->i_data[11] = 0;
1.1 root 158: }
159: return result;
160: }
161:
162: void ext_truncate(struct inode * inode)
163: {
164: int flag;
165:
166: if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
167: S_ISLNK(inode->i_mode)))
168: return;
169: /* if (inode->i_data[7] & 0xffff0000)
170: printk("BAD! ext inode has 16 high bits set\n"); */
171: while (1) {
172: flag = trunc_direct(inode);
173: flag |= trunc_indirect(inode,9,(unsigned long *)&inode->i_data[9]);
1.1.1.2 ! root 174: flag |= trunc_dindirect(inode,9+256,(unsigned long *)&inode->i_data[10]);
! 175: flag |= trunc_tindirect(inode);
1.1 root 176: if (!flag)
177: break;
178: current->counter = 0;
179: schedule();
180: }
181: inode->i_mtime = inode->i_ctime = CURRENT_TIME;
182: inode->i_dirt = 1;
183: }
184:
185: /*
186: * Called when a inode is released. Note that this is different
187: * from ext_open: open gets called at every open, but release
188: * gets called only when /all/ the files are closed.
189: */
190: void ext_release(struct inode * inode, struct file * filp)
191: {
192: printk("ext_release not implemented\n");
193: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.