|
|
1.1 ! root 1: /* ! 2: * linux/fs/ext/truncate.c ! 3: * ! 4: * (C) 1992 Remy Card ([email protected]) ! 5: * ! 6: * from ! 7: * ! 8: * linux/fs/minix/truncate.c ! 9: * ! 10: * (C) 1991 Linus Torvalds ! 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> ! 18: ! 19: #include <errno.h> ! 20: ! 21: /* ! 22: * Truncate has the most races in the whole filesystem: coding it is ! 23: * a pain in the a**. Especially as I don't do any locking... ! 24: * ! 25: * The code may look a bit weird, but that's just because I've tried to ! 26: * handle things like file-size changes in a somewhat graceful manner. ! 27: * Anyway, truncating a file at the same time somebody else writes to it ! 28: * is likely to result in pretty weird behaviour... ! 29: * ! 30: * The new code handles normal truncates (size = 0) as well as the more ! 31: * general case (size = XXX). I hope. ! 32: */ ! 33: ! 34: static int trunc_direct(struct inode * inode) ! 35: { ! 36: int i; ! 37: int result = 0; ! 38: #define DIRECT_BLOCK ((inode->i_size + 1023) >> 10) ! 39: ! 40: repeat: ! 41: for (i = DIRECT_BLOCK ; i < 9 ; i++) { ! 42: if (i < DIRECT_BLOCK) ! 43: goto repeat; ! 44: if (!inode->i_data[i]) ! 45: continue; ! 46: result = 1; ! 47: if (ext_free_block(inode->i_dev,inode->i_data[i])) ! 48: inode->i_data[i] = 0; ! 49: } ! 50: return result; ! 51: } ! 52: ! 53: static int trunc_indirect(struct inode * inode, int offset, unsigned long * p) ! 54: { ! 55: int i; ! 56: struct buffer_head * bh = NULL; ! 57: unsigned long * ind; ! 58: int result = 0; ! 59: #define INDIRECT_BLOCK (DIRECT_BLOCK-offset) ! 60: ! 61: if (*p) ! 62: bh = bread(inode->i_dev,*p); ! 63: if (!bh) ! 64: return 0; ! 65: repeat: ! 66: for (i = INDIRECT_BLOCK ; i < 256 ; i++) { ! 67: if (i < 0) ! 68: i = 0; ! 69: if (i < INDIRECT_BLOCK) ! 70: goto repeat; ! 71: ind = i+(unsigned long *) bh->b_data; ! 72: if (!*ind) ! 73: continue; ! 74: result = 1; ! 75: if (ext_free_block(inode->i_dev,*ind)) ! 76: *ind = 0; ! 77: } ! 78: ind = (unsigned long *) bh->b_data; ! 79: for (i = 0; i < 256; i++) ! 80: if (*(ind++)) ! 81: break; ! 82: brelse(bh); ! 83: if (i >= 256) { ! 84: result = 1; ! 85: if (ext_free_block(inode->i_dev,*p)) ! 86: *p = 0; ! 87: } ! 88: return result; ! 89: } ! 90: ! 91: static int trunc_dindirect(struct inode * inode) ! 92: { ! 93: int i; ! 94: struct buffer_head * bh = NULL; ! 95: unsigned long * dind; ! 96: int result = 0; ! 97: #define DINDIRECT_BLOCK ((DIRECT_BLOCK-(256+9))>>8) ! 98: ! 99: if (inode->i_data[10]) ! 100: bh = bread(inode->i_dev,inode->i_data[10]); ! 101: if (!bh) ! 102: return 0; ! 103: repeat: ! 104: for (i = DINDIRECT_BLOCK ; i < 256 ; i ++) { ! 105: if (i < 0) ! 106: i = 0; ! 107: if (i < DINDIRECT_BLOCK) ! 108: goto repeat; ! 109: dind = i+(unsigned long *) bh->b_data; ! 110: if (!*dind) ! 111: continue; ! 112: result |= trunc_indirect(inode,9+256+(i<<8),dind); ! 113: } ! 114: dind = (unsigned long *) bh->b_data; ! 115: for (i = 0; i < 256; i++) ! 116: if (*(dind++)) ! 117: break; ! 118: brelse(bh); ! 119: if (i >= 256) { ! 120: result = 1; ! 121: if (ext_free_block(inode->i_dev,inode->i_data[10])) ! 122: inode->i_data[10] = 0; ! 123: } ! 124: return result; ! 125: } ! 126: ! 127: void ext_truncate(struct inode * inode) ! 128: { ! 129: int flag; ! 130: ! 131: if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || ! 132: S_ISLNK(inode->i_mode))) ! 133: return; ! 134: /* if (inode->i_data[7] & 0xffff0000) ! 135: printk("BAD! ext inode has 16 high bits set\n"); */ ! 136: while (1) { ! 137: flag = trunc_direct(inode); ! 138: flag |= trunc_indirect(inode,9,(unsigned long *)&inode->i_data[9]); ! 139: flag |= trunc_dindirect(inode); ! 140: if (!flag) ! 141: break; ! 142: current->counter = 0; ! 143: schedule(); ! 144: } ! 145: inode->i_mtime = inode->i_ctime = CURRENT_TIME; ! 146: inode->i_dirt = 1; ! 147: } ! 148: ! 149: /* ! 150: * Called when a inode is released. Note that this is different ! 151: * from ext_open: open gets called at every open, but release ! 152: * gets called only when /all/ the files are closed. ! 153: */ ! 154: void ext_release(struct inode * inode, struct file * filp) ! 155: { ! 156: printk("ext_release not implemented\n"); ! 157: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.