/*
|
/*
|
* linux/fs/truncate.c
|
* linux/fs/truncate.c
|
*
|
*
|
* Copyright (C) 1991, 1992 Linus Torvalds
|
* Copyright (C) 1991, 1992 Linus Torvalds
|
*
|
*
|
* Copyright (C) 1996 Gertjan van Wingerde (gertjan@cs.vu.nl)
|
* Copyright (C) 1996 Gertjan van Wingerde (gertjan@cs.vu.nl)
|
* Minix V2 fs support.
|
* Minix V2 fs support.
|
*/
|
*/
|
|
|
#include <linux/errno.h>
|
#include <linux/errno.h>
|
#include <linux/sched.h>
|
#include <linux/sched.h>
|
#include <linux/minix_fs.h>
|
#include <linux/minix_fs.h>
|
#include <linux/stat.h>
|
#include <linux/stat.h>
|
#include <linux/fcntl.h>
|
#include <linux/fcntl.h>
|
|
|
#define DIRECT_BLOCK ((inode->i_size + 1023) >> 10)
|
#define DIRECT_BLOCK ((inode->i_size + 1023) >> 10)
|
#define INDIRECT_BLOCK(offset) (DIRECT_BLOCK-offset)
|
#define INDIRECT_BLOCK(offset) (DIRECT_BLOCK-offset)
|
#define V1_DINDIRECT_BLOCK(offset) ((DIRECT_BLOCK-offset)>>9)
|
#define V1_DINDIRECT_BLOCK(offset) ((DIRECT_BLOCK-offset)>>9)
|
#define V2_DINDIRECT_BLOCK(offset) ((DIRECT_BLOCK-offset)>>8)
|
#define V2_DINDIRECT_BLOCK(offset) ((DIRECT_BLOCK-offset)>>8)
|
#define TINDIRECT_BLOCK(offset) ((DIRECT_BLOCK-(offset))>>8)
|
#define TINDIRECT_BLOCK(offset) ((DIRECT_BLOCK-(offset))>>8)
|
|
|
/*
|
/*
|
* 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.
|
*/
|
*/
|
|
|
/*
|
/*
|
* The functions for minix V1 fs truncation.
|
* The functions for minix V1 fs truncation.
|
*/
|
*/
|
static int V1_trunc_direct(struct inode * inode)
|
static int V1_trunc_direct(struct inode * inode)
|
{
|
{
|
unsigned short * p;
|
unsigned short * p;
|
struct buffer_head * bh;
|
struct buffer_head * bh;
|
int i, tmp;
|
int i, tmp;
|
int retry = 0;
|
int retry = 0;
|
|
|
repeat:
|
repeat:
|
for (i = DIRECT_BLOCK ; i < 7 ; i++) {
|
for (i = DIRECT_BLOCK ; i < 7 ; i++) {
|
p = i + inode->u.minix_i.u.i1_data;
|
p = i + inode->u.minix_i.u.i1_data;
|
if (!(tmp = *p))
|
if (!(tmp = *p))
|
continue;
|
continue;
|
bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
|
bh = get_hash_table(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;
|
if (bh) {
|
if (bh) {
|
mark_buffer_clean(bh);
|
mark_buffer_clean(bh);
|
brelse(bh);
|
brelse(bh);
|
}
|
}
|
minix_free_block(inode->i_sb,tmp);
|
minix_free_block(inode->i_sb,tmp);
|
}
|
}
|
return retry;
|
return retry;
|
}
|
}
|
|
|
static int V1_trunc_indirect(struct inode * inode, int offset, unsigned short * p)
|
static int V1_trunc_indirect(struct inode * inode, int offset, unsigned short * p)
|
{
|
{
|
struct buffer_head * bh;
|
struct buffer_head * bh;
|
int i, tmp;
|
int i, tmp;
|
struct buffer_head * ind_bh;
|
struct buffer_head * ind_bh;
|
unsigned short * ind;
|
unsigned short * ind;
|
int retry = 0;
|
int retry = 0;
|
|
|
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(offset) ; i < 512 ; i++) {
|
for (i = INDIRECT_BLOCK(offset) ; i < 512 ; i++) {
|
if (i < 0)
|
if (i < 0)
|
i = 0;
|
i = 0;
|
if (i < INDIRECT_BLOCK(offset))
|
if (i < INDIRECT_BLOCK(offset))
|
goto repeat;
|
goto repeat;
|
ind = i+(unsigned short *) ind_bh->b_data;
|
ind = i+(unsigned short *) ind_bh->b_data;
|
tmp = *ind;
|
tmp = *ind;
|
if (!tmp)
|
if (!tmp)
|
continue;
|
continue;
|
bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
|
bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
|
if (i < INDIRECT_BLOCK(offset)) {
|
if (i < INDIRECT_BLOCK(offset)) {
|
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);
|
minix_free_block(inode->i_sb,tmp);
|
minix_free_block(inode->i_sb,tmp);
|
}
|
}
|
ind = (unsigned short *) ind_bh->b_data;
|
ind = (unsigned short *) ind_bh->b_data;
|
for (i = 0; i < 512; i++)
|
for (i = 0; i < 512; i++)
|
if (*(ind++))
|
if (*(ind++))
|
break;
|
break;
|
if (i >= 512)
|
if (i >= 512)
|
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;
|
minix_free_block(inode->i_sb,tmp);
|
minix_free_block(inode->i_sb,tmp);
|
}
|
}
|
brelse(ind_bh);
|
brelse(ind_bh);
|
return retry;
|
return retry;
|
}
|
}
|
|
|
static int V1_trunc_dindirect(struct inode * inode, int offset, unsigned short *p)
|
static int V1_trunc_dindirect(struct inode * inode, int offset, unsigned short *p)
|
{
|
{
|
int i, tmp;
|
int i, tmp;
|
struct buffer_head * dind_bh;
|
struct buffer_head * dind_bh;
|
unsigned short * dind;
|
unsigned short * dind;
|
int retry = 0;
|
int retry = 0;
|
|
|
if (!(tmp = *p))
|
if (!(tmp = *p))
|
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 = V1_DINDIRECT_BLOCK(offset) ; i < 512 ; i ++) {
|
for (i = V1_DINDIRECT_BLOCK(offset) ; i < 512 ; i ++) {
|
if (i < 0)
|
if (i < 0)
|
i = 0;
|
i = 0;
|
if (i < V1_DINDIRECT_BLOCK(offset))
|
if (i < V1_DINDIRECT_BLOCK(offset))
|
goto repeat;
|
goto repeat;
|
dind = i+(unsigned short *) dind_bh->b_data;
|
dind = i+(unsigned short *) dind_bh->b_data;
|
retry |= V1_trunc_indirect(inode,offset+(i<<9),dind);
|
retry |= V1_trunc_indirect(inode,offset+(i<<9),dind);
|
mark_buffer_dirty(dind_bh, 1);
|
mark_buffer_dirty(dind_bh, 1);
|
}
|
}
|
dind = (unsigned short *) dind_bh->b_data;
|
dind = (unsigned short *) dind_bh->b_data;
|
for (i = 0; i < 512; i++)
|
for (i = 0; i < 512; i++)
|
if (*(dind++))
|
if (*(dind++))
|
break;
|
break;
|
if (i >= 512)
|
if (i >= 512)
|
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;
|
minix_free_block(inode->i_sb,tmp);
|
minix_free_block(inode->i_sb,tmp);
|
}
|
}
|
brelse(dind_bh);
|
brelse(dind_bh);
|
return retry;
|
return retry;
|
}
|
}
|
|
|
void V1_minix_truncate(struct inode * inode)
|
void V1_minix_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 = V1_trunc_direct(inode);
|
retry = V1_trunc_direct(inode);
|
retry |= V1_trunc_indirect(inode, 7, inode->u.minix_i.u.i1_data + 7);
|
retry |= V1_trunc_indirect(inode, 7, inode->u.minix_i.u.i1_data + 7);
|
retry |= V1_trunc_dindirect(inode, 7+512, inode->u.minix_i.u.i1_data + 8);
|
retry |= V1_trunc_dindirect(inode, 7+512, inode->u.minix_i.u.i1_data + 8);
|
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;
|
}
|
}
|
|
|
/*
|
/*
|
* The functions for minix V2 fs truncation.
|
* The functions for minix V2 fs truncation.
|
*/
|
*/
|
static int V2_trunc_direct(struct inode * inode)
|
static int V2_trunc_direct(struct inode * inode)
|
{
|
{
|
unsigned long * p;
|
unsigned long * p;
|
struct buffer_head * bh;
|
struct buffer_head * bh;
|
int i, tmp;
|
int i, tmp;
|
int retry = 0;
|
int retry = 0;
|
|
|
repeat:
|
repeat:
|
for (i = DIRECT_BLOCK ; i < 7 ; i++) {
|
for (i = DIRECT_BLOCK ; i < 7 ; i++) {
|
p = (unsigned long *) inode->u.minix_i.u.i2_data + i;
|
p = (unsigned long *) inode->u.minix_i.u.i2_data + i;
|
if (!(tmp = *p))
|
if (!(tmp = *p))
|
continue;
|
continue;
|
bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
|
bh = get_hash_table(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;
|
if (bh) {
|
if (bh) {
|
mark_buffer_clean(bh);
|
mark_buffer_clean(bh);
|
brelse(bh);
|
brelse(bh);
|
}
|
}
|
minix_free_block(inode->i_sb,tmp);
|
minix_free_block(inode->i_sb,tmp);
|
}
|
}
|
return retry;
|
return retry;
|
}
|
}
|
|
|
static int V2_trunc_indirect(struct inode * inode, int offset, unsigned long * p)
|
static int V2_trunc_indirect(struct inode * inode, int offset, unsigned long * p)
|
{
|
{
|
struct buffer_head * bh;
|
struct buffer_head * bh;
|
int i, tmp;
|
int i, tmp;
|
struct buffer_head * ind_bh;
|
struct buffer_head * ind_bh;
|
unsigned long * ind;
|
unsigned long * ind;
|
int retry = 0;
|
int retry = 0;
|
|
|
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(offset) ; i < 256 ; i++) {
|
for (i = INDIRECT_BLOCK(offset) ; i < 256 ; i++) {
|
if (i < 0)
|
if (i < 0)
|
i = 0;
|
i = 0;
|
if (i < INDIRECT_BLOCK(offset))
|
if (i < INDIRECT_BLOCK(offset))
|
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 = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
|
bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
|
if (i < INDIRECT_BLOCK(offset)) {
|
if (i < INDIRECT_BLOCK(offset)) {
|
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);
|
minix_free_block(inode->i_sb,tmp);
|
minix_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;
|
minix_free_block(inode->i_sb,tmp);
|
minix_free_block(inode->i_sb,tmp);
|
}
|
}
|
brelse(ind_bh);
|
brelse(ind_bh);
|
return retry;
|
return retry;
|
}
|
}
|
|
|
static int V2_trunc_dindirect(struct inode * inode, int offset, unsigned long *p)
|
static int V2_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;
|
|
|
if (!(tmp = *p))
|
if (!(tmp = *p))
|
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 = V2_DINDIRECT_BLOCK(offset) ; i < 256 ; i ++) {
|
for (i = V2_DINDIRECT_BLOCK(offset) ; i < 256 ; i ++) {
|
if (i < 0)
|
if (i < 0)
|
i = 0;
|
i = 0;
|
if (i < V2_DINDIRECT_BLOCK(offset))
|
if (i < V2_DINDIRECT_BLOCK(offset))
|
goto repeat;
|
goto repeat;
|
dind = i+(unsigned long *) dind_bh->b_data;
|
dind = i+(unsigned long *) dind_bh->b_data;
|
retry |= V2_trunc_indirect(inode,offset+(i<<8),dind);
|
retry |= V2_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;
|
minix_free_block(inode->i_sb,tmp);
|
minix_free_block(inode->i_sb,tmp);
|
}
|
}
|
brelse(dind_bh);
|
brelse(dind_bh);
|
return retry;
|
return retry;
|
}
|
}
|
|
|
static int V2_trunc_tindirect(struct inode * inode, int offset, unsigned long * p)
|
static int V2_trunc_tindirect(struct inode * inode, int offset, unsigned long * p)
|
{
|
{
|
int i, tmp;
|
int i, tmp;
|
struct buffer_head * tind_bh;
|
struct buffer_head * tind_bh;
|
unsigned long * tind;
|
unsigned long * tind;
|
int retry = 0;
|
int retry = 0;
|
|
|
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(offset) ; i < 256 ; i ++) {
|
for (i = TINDIRECT_BLOCK(offset) ; i < 256 ; i ++) {
|
if (i < 0)
|
if (i < 0)
|
i = 0;
|
i = 0;
|
if (i < TINDIRECT_BLOCK(offset))
|
if (i < TINDIRECT_BLOCK(offset))
|
goto repeat;
|
goto repeat;
|
tind = i+(unsigned long *) tind_bh->b_data;
|
tind = i+(unsigned long *) tind_bh->b_data;
|
retry |= V2_trunc_dindirect(inode,offset+(i<<8),tind);
|
retry |= V2_trunc_dindirect(inode,offset+(i<<8),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;
|
minix_free_block(inode->i_sb,tmp);
|
minix_free_block(inode->i_sb,tmp);
|
}
|
}
|
brelse(tind_bh);
|
brelse(tind_bh);
|
return retry;
|
return retry;
|
}
|
}
|
|
|
static void V2_minix_truncate(struct inode * inode)
|
static void V2_minix_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 = V2_trunc_direct(inode);
|
retry = V2_trunc_direct(inode);
|
retry |= V2_trunc_indirect(inode,7,
|
retry |= V2_trunc_indirect(inode,7,
|
(unsigned long *) inode->u.minix_i.u.i2_data + 7);
|
(unsigned long *) inode->u.minix_i.u.i2_data + 7);
|
retry |= V2_trunc_dindirect(inode, 7+256,
|
retry |= V2_trunc_dindirect(inode, 7+256,
|
(unsigned long *) inode->u.minix_i.u.i2_data + 8);
|
(unsigned long *) inode->u.minix_i.u.i2_data + 8);
|
retry |= V2_trunc_tindirect(inode, 7+256+256*256,
|
retry |= V2_trunc_tindirect(inode, 7+256+256*256,
|
(unsigned long *) inode->u.minix_i.u.i2_data + 9);
|
(unsigned long *) inode->u.minix_i.u.i2_data + 9);
|
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;
|
}
|
}
|
|
|
/*
|
/*
|
* The function that is called for file truncation.
|
* The function that is called for file truncation.
|
*/
|
*/
|
void minix_truncate(struct inode * inode)
|
void minix_truncate(struct inode * inode)
|
{
|
{
|
if (INODE_VERSION(inode) == MINIX_V1)
|
if (INODE_VERSION(inode) == MINIX_V1)
|
V1_minix_truncate(inode);
|
V1_minix_truncate(inode);
|
else
|
else
|
V2_minix_truncate(inode);
|
V2_minix_truncate(inode);
|
}
|
}
|
|
|