OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [rc203soc/] [sw/] [uClinux/] [fs/] [ext/] [truncate.c] - Diff between revs 1765 and 1782

Only display areas with differences | Details | Blame | View Log

Rev 1765 Rev 1782
/*
/*
 *  linux/fs/ext/truncate.c
 *  linux/fs/ext/truncate.c
 *
 *
 *  Copyright (C) 1992  Remy Card (card@masi.ibp.fr)
 *  Copyright (C) 1992  Remy Card (card@masi.ibp.fr)
 *
 *
 *  from
 *  from
 *
 *
 *  linux/fs/minix/truncate.c
 *  linux/fs/minix/truncate.c
 *
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 *  Copyright (C) 1991, 1992  Linus Torvalds
 */
 */
 
 
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/ext_fs.h>
#include <linux/ext_fs.h>
#include <linux/stat.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/fcntl.h>
#include <linux/errno.h>
#include <linux/errno.h>
 
 
/*
/*
 * Truncate has the most races in the whole filesystem: coding it is
 * Truncate has the most races in the whole filesystem: coding it is
 * a pain in the a**. Especially as I don't do any locking...
 * a pain in the a**. Especially as I don't do any locking...
 *
 *
 * The code may look a bit weird, but that's just because I've tried to
 * The code may look a bit weird, but that's just because I've tried to
 * handle things like file-size changes in a somewhat graceful manner.
 * handle things like file-size changes in a somewhat graceful manner.
 * Anyway, truncating a file at the same time somebody else writes to it
 * Anyway, truncating a file at the same time somebody else writes to it
 * is likely to result in pretty weird behaviour...
 * is likely to result in pretty weird behaviour...
 *
 *
 * The new code handles normal truncates (size = 0) as well as the more
 * The new code handles normal truncates (size = 0) as well as the more
 * general case (size = XXX). I hope.
 * general case (size = XXX). I hope.
 */
 */
 
 
static int trunc_direct(struct inode * inode)
static int trunc_direct(struct inode * inode)
{
{
        int i, tmp;
        int i, tmp;
        unsigned long * p;
        unsigned long * p;
        struct buffer_head * bh;
        struct buffer_head * bh;
        int retry = 0;
        int retry = 0;
#define DIRECT_BLOCK ((inode->i_size + 1023) >> 10)
#define DIRECT_BLOCK ((inode->i_size + 1023) >> 10)
 
 
repeat:
repeat:
        for (i = DIRECT_BLOCK ; i < 9 ; i++) {
        for (i = DIRECT_BLOCK ; i < 9 ; i++) {
                p = inode->u.ext_i.i_data+i;
                p = inode->u.ext_i.i_data+i;
                if (!(tmp = *p))
                if (!(tmp = *p))
                        continue;
                        continue;
                bh = getblk(inode->i_dev,tmp,BLOCK_SIZE);
                bh = getblk(inode->i_dev,tmp,BLOCK_SIZE);
                if (i < DIRECT_BLOCK) {
                if (i < DIRECT_BLOCK) {
                        brelse(bh);
                        brelse(bh);
                        goto repeat;
                        goto repeat;
                }
                }
                if ((bh && bh->b_count != 1) || tmp != *p) {
                if ((bh && bh->b_count != 1) || tmp != *p) {
                        retry = 1;
                        retry = 1;
                        brelse(bh);
                        brelse(bh);
                        continue;
                        continue;
                }
                }
                *p = 0;
                *p = 0;
                inode->i_dirt = 1;
                inode->i_dirt = 1;
                brelse(bh);
                brelse(bh);
                ext_free_block(inode->i_sb,tmp);
                ext_free_block(inode->i_sb,tmp);
        }
        }
        return retry;
        return retry;
}
}
 
 
static int trunc_indirect(struct inode * inode, int offset, unsigned long * p)
static int trunc_indirect(struct inode * inode, int offset, unsigned long * p)
{
{
        int i, tmp;
        int i, tmp;
        struct buffer_head * bh;
        struct buffer_head * bh;
        struct buffer_head * ind_bh;
        struct buffer_head * ind_bh;
        unsigned long * ind;
        unsigned long * ind;
        int retry = 0;
        int retry = 0;
#define INDIRECT_BLOCK (DIRECT_BLOCK-offset)
#define INDIRECT_BLOCK (DIRECT_BLOCK-offset)
 
 
        tmp = *p;
        tmp = *p;
        if (!tmp)
        if (!tmp)
                return 0;
                return 0;
        ind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
        ind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
        if (tmp != *p) {
        if (tmp != *p) {
                brelse(ind_bh);
                brelse(ind_bh);
                return 1;
                return 1;
        }
        }
        if (!ind_bh) {
        if (!ind_bh) {
                *p = 0;
                *p = 0;
                return 0;
                return 0;
        }
        }
repeat:
repeat:
        for (i = INDIRECT_BLOCK ; i < 256 ; i++) {
        for (i = INDIRECT_BLOCK ; i < 256 ; i++) {
                if (i < 0)
                if (i < 0)
                        i = 0;
                        i = 0;
                if (i < INDIRECT_BLOCK)
                if (i < INDIRECT_BLOCK)
                        goto repeat;
                        goto repeat;
                ind = i+(unsigned long *) ind_bh->b_data;
                ind = i+(unsigned long *) ind_bh->b_data;
                tmp = *ind;
                tmp = *ind;
                if (!tmp)
                if (!tmp)
                        continue;
                        continue;
                bh = getblk(inode->i_dev,tmp,BLOCK_SIZE);
                bh = getblk(inode->i_dev,tmp,BLOCK_SIZE);
                if (i < INDIRECT_BLOCK) {
                if (i < INDIRECT_BLOCK) {
                        brelse(bh);
                        brelse(bh);
                        goto repeat;
                        goto repeat;
                }
                }
                if ((bh && bh->b_count != 1) || tmp != *ind) {
                if ((bh && bh->b_count != 1) || tmp != *ind) {
                        retry = 1;
                        retry = 1;
                        brelse(bh);
                        brelse(bh);
                        continue;
                        continue;
                }
                }
                *ind = 0;
                *ind = 0;
                mark_buffer_dirty(ind_bh, 1);
                mark_buffer_dirty(ind_bh, 1);
                brelse(bh);
                brelse(bh);
                ext_free_block(inode->i_sb,tmp);
                ext_free_block(inode->i_sb,tmp);
        }
        }
        ind = (unsigned long *) ind_bh->b_data;
        ind = (unsigned long *) ind_bh->b_data;
        for (i = 0; i < 256; i++)
        for (i = 0; i < 256; i++)
                if (*(ind++))
                if (*(ind++))
                        break;
                        break;
        if (i >= 256)
        if (i >= 256)
                if (ind_bh->b_count != 1)
                if (ind_bh->b_count != 1)
                        retry = 1;
                        retry = 1;
                else {
                else {
                        tmp = *p;
                        tmp = *p;
                        *p = 0;
                        *p = 0;
                        inode->i_dirt = 1;
                        inode->i_dirt = 1;
                        ext_free_block(inode->i_sb,tmp);
                        ext_free_block(inode->i_sb,tmp);
                }
                }
        brelse(ind_bh);
        brelse(ind_bh);
        return retry;
        return retry;
}
}
 
 
static int trunc_dindirect(struct inode * inode, int offset, unsigned long * p)
static int trunc_dindirect(struct inode * inode, int offset, unsigned long * p)
{
{
        int i,tmp;
        int i,tmp;
        struct buffer_head * dind_bh;
        struct buffer_head * dind_bh;
        unsigned long * dind;
        unsigned long * dind;
        int retry = 0;
        int retry = 0;
#define DINDIRECT_BLOCK ((DIRECT_BLOCK-offset)>>8)
#define DINDIRECT_BLOCK ((DIRECT_BLOCK-offset)>>8)
 
 
        tmp = *p;
        tmp = *p;
        if (!tmp)
        if (!tmp)
                return 0;
                return 0;
        dind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
        dind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
        if (tmp != *p) {
        if (tmp != *p) {
                brelse(dind_bh);
                brelse(dind_bh);
                return 1;
                return 1;
        }
        }
        if (!dind_bh) {
        if (!dind_bh) {
                *p = 0;
                *p = 0;
                return 0;
                return 0;
        }
        }
repeat:
repeat:
        for (i = DINDIRECT_BLOCK ; i < 256 ; i ++) {
        for (i = DINDIRECT_BLOCK ; i < 256 ; i ++) {
                if (i < 0)
                if (i < 0)
                        i = 0;
                        i = 0;
                if (i < DINDIRECT_BLOCK)
                if (i < DINDIRECT_BLOCK)
                        goto repeat;
                        goto repeat;
                dind = i+(unsigned long *) dind_bh->b_data;
                dind = i+(unsigned long *) dind_bh->b_data;
                tmp = *dind;
                tmp = *dind;
                if (!tmp)
                if (!tmp)
                        continue;
                        continue;
                retry |= trunc_indirect(inode,offset+(i<<8),dind);
                retry |= trunc_indirect(inode,offset+(i<<8),dind);
                mark_buffer_dirty(dind_bh, 1);
                mark_buffer_dirty(dind_bh, 1);
        }
        }
        dind = (unsigned long *) dind_bh->b_data;
        dind = (unsigned long *) dind_bh->b_data;
        for (i = 0; i < 256; i++)
        for (i = 0; i < 256; i++)
                if (*(dind++))
                if (*(dind++))
                        break;
                        break;
        if (i >= 256)
        if (i >= 256)
                if (dind_bh->b_count != 1)
                if (dind_bh->b_count != 1)
                        retry = 1;
                        retry = 1;
                else {
                else {
                        tmp = *p;
                        tmp = *p;
                        *p = 0;
                        *p = 0;
                        inode->i_dirt = 1;
                        inode->i_dirt = 1;
                        ext_free_block(inode->i_sb,tmp);
                        ext_free_block(inode->i_sb,tmp);
                }
                }
        brelse(dind_bh);
        brelse(dind_bh);
        return retry;
        return retry;
}
}
 
 
static int trunc_tindirect(struct inode * inode)
static int trunc_tindirect(struct inode * inode)
{
{
        int i,tmp;
        int i,tmp;
        struct buffer_head * tind_bh;
        struct buffer_head * tind_bh;
        unsigned long * tind, * p;
        unsigned long * tind, * p;
        int retry = 0;
        int retry = 0;
#define TINDIRECT_BLOCK ((DIRECT_BLOCK-(256*256+256+9))>>16)
#define TINDIRECT_BLOCK ((DIRECT_BLOCK-(256*256+256+9))>>16)
 
 
        p = inode->u.ext_i.i_data+11;
        p = inode->u.ext_i.i_data+11;
        if (!(tmp = *p))
        if (!(tmp = *p))
                return 0;
                return 0;
        tind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
        tind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
        if (tmp != *p) {
        if (tmp != *p) {
                brelse(tind_bh);
                brelse(tind_bh);
                return 1;
                return 1;
        }
        }
        if (!tind_bh) {
        if (!tind_bh) {
                *p = 0;
                *p = 0;
                return 0;
                return 0;
        }
        }
repeat:
repeat:
        for (i = TINDIRECT_BLOCK ; i < 256 ; i ++) {
        for (i = TINDIRECT_BLOCK ; i < 256 ; i ++) {
                if (i < 0)
                if (i < 0)
                        i = 0;
                        i = 0;
                if (i < TINDIRECT_BLOCK)
                if (i < TINDIRECT_BLOCK)
                        goto repeat;
                        goto repeat;
                tind = i+(unsigned long *) tind_bh->b_data;
                tind = i+(unsigned long *) tind_bh->b_data;
                retry |= trunc_dindirect(inode,9+256+256*256+(i<<16),tind);
                retry |= trunc_dindirect(inode,9+256+256*256+(i<<16),tind);
                mark_buffer_dirty(tind_bh, 1);
                mark_buffer_dirty(tind_bh, 1);
        }
        }
        tind = (unsigned long *) tind_bh->b_data;
        tind = (unsigned long *) tind_bh->b_data;
        for (i = 0; i < 256; i++)
        for (i = 0; i < 256; i++)
                if (*(tind++))
                if (*(tind++))
                        break;
                        break;
        if (i >= 256)
        if (i >= 256)
                if (tind_bh->b_count != 1)
                if (tind_bh->b_count != 1)
                        retry = 1;
                        retry = 1;
                else {
                else {
                        tmp = *p;
                        tmp = *p;
                        *p = 0;
                        *p = 0;
                        inode->i_dirt = 1;
                        inode->i_dirt = 1;
                        ext_free_block(inode->i_sb,tmp);
                        ext_free_block(inode->i_sb,tmp);
                }
                }
        brelse(tind_bh);
        brelse(tind_bh);
        return retry;
        return retry;
}
}
 
 
void ext_truncate(struct inode * inode)
void ext_truncate(struct inode * inode)
{
{
        int retry;
        int retry;
 
 
        if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
        if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
             S_ISLNK(inode->i_mode)))
             S_ISLNK(inode->i_mode)))
                return;
                return;
        while (1) {
        while (1) {
                retry = trunc_direct(inode);
                retry = trunc_direct(inode);
                retry |= trunc_indirect(inode,9,inode->u.ext_i.i_data+9);
                retry |= trunc_indirect(inode,9,inode->u.ext_i.i_data+9);
                retry |= trunc_dindirect(inode,9+256,inode->u.ext_i.i_data+10);
                retry |= trunc_dindirect(inode,9+256,inode->u.ext_i.i_data+10);
                retry |= trunc_tindirect(inode);
                retry |= trunc_tindirect(inode);
                if (!retry)
                if (!retry)
                        break;
                        break;
                current->counter = 0;
                current->counter = 0;
                schedule();
                schedule();
        }
        }
        inode->i_mtime = inode->i_ctime = CURRENT_TIME;
        inode->i_mtime = inode->i_ctime = CURRENT_TIME;
        inode->i_dirt = 1;
        inode->i_dirt = 1;
}
}
 
 
/*
/*
 * Called when a inode is released. Note that this is different
 * Called when a inode is released. Note that this is different
 * from ext_open: open gets called at every open, but release
 * from ext_open: open gets called at every open, but release
 * gets called only when /all/ the files are closed.
 * gets called only when /all/ the files are closed.
 */
 */
void ext_release(struct inode * inode, struct file * filp)
void ext_release(struct inode * inode, struct file * filp)
{
{
        printk("ext_release not implemented\n");
        printk("ext_release not implemented\n");
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.