Annotation of linux/fs/ext/truncate.c, revision 1.1.1.3

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.