static int trunc_all(struct inode * inode) { return trunc_direct(inode) | trunc_indirect(inode,10*BLOCK_SIZE,&inode->u.sysv_i.i_data[10],0,&inode->i_dirt) | trunc_dindirect(inode,(10+IND_PER_BLOCK)*BLOCK_SIZE,&inode->u.sysv_i.i_data[11],0,&inode->i_dirt) | trunc_tindirect(inode,(10+IND_PER_BLOCK+IND_PER_BLOCK*IND_PER_BLOCK)*BLOCK_SIZE,&inode->u.sysv_i.i_data[12],0,&inode->i_dirt); }
static int trunc_dindirect(struct inode * inode, unsigned long offset, sysv_zone_t * p, int convert, unsigned char * dirt) { u32 indtmp, indblock; struct super_block * sb; struct buffer_head * indbh; unsigned int i; sysv_zone_t * ind; u32 tmp, block; int retry = 0; indblock = indtmp = *p; if (convert) indblock = from_coh_ulong(indblock); if (!indblock) return 0; sb = inode->i_sb; indbh = sv_bread(sb, inode->i_dev, indblock); if (indtmp != *p) { brelse(indbh); return 1; } if (!indbh) { *p = 0; *dirt = 1; return 0; } if (inode->i_size < offset) i = 0; else i = (inode->i_size - offset + sb->sv_ind_per_block_block_size_1) >> sb->sv_ind_per_block_block_size_bits; for (; i < sb->sv_ind_per_block; i++) { unsigned char dirty = 0; ind = ((sysv_zone_t *) indbh->b_data) + i; block = tmp = *ind; if (sb->sv_convert) block = from_coh_ulong(block); if (!block) continue; retry |= trunc_indirect(inode,offset+(i<<sb->sv_ind_per_block_bits),ind,sb->sv_convert,&dirty); if (dirty) mark_buffer_dirty(indbh, 1); } for (i = 0; i < sb->sv_ind_per_block; i++) if (((sysv_zone_t *) indbh->b_data)[i]) goto done; if ((indbh->b_count != 1) || (indtmp != *p)) { brelse(indbh); return 1; } *p = 0; *dirt = 1; sysv_free_block(sb,indblock); done: brelse(indbh); return retry; }
static int trunc_all(struct inode * inode) { struct super_block * sb; char dirty; sb = inode->i_sb; return trunc_direct(inode) | trunc_indirect(inode,sb->sv_ind0_size,&inode->u.sysv_i.i_data[10],0,&dirty) | trunc_dindirect(inode,sb->sv_ind1_size,&inode->u.sysv_i.i_data[11],0,&dirty) | trunc_tindirect(inode,sb->sv_ind2_size,&inode->u.sysv_i.i_data[12],0,&dirty); }
static int trunc_dindirect(struct inode * inode, unsigned long offset, unsigned long * p, int convert, unsigned char * dirt) { unsigned long indtmp, indblock; struct super_block * sb; struct buffer_head * indbh; unsigned int i; sysv_zone_t * ind; unsigned long tmp, block; int retry = 0; indblock = indtmp = *p; if (convert) indblock = from_coh_ulong(indblock); if (!indblock) return 0; sb = inode->i_sb; indbh = bread(inode->i_dev,indblock+sb->sv_block_base,BLOCK_SIZE); if (indtmp != *p) { brelse(indbh); return 1; } if (!indbh) { *p = 0; *dirt = 1; return 0; } if (inode->i_size < offset) i = 0; else i = (inode->i_size - offset + IND_PER_BLOCK*BLOCK_SIZE-1) / (IND_PER_BLOCK*BLOCK_SIZE); for (; i < IND_PER_BLOCK; i++) { ind = ((sysv_zone_t *) indbh->b_data) + i; block = tmp = *ind; if (sb->sv_convert) block = from_coh_ulong(block); if (!block) continue; retry |= trunc_indirect(inode,offset+i*IND_PER_BLOCK,ind,sb->sv_convert,&indbh->b_dirt); } for (i = 0; i < IND_PER_BLOCK; i++) if (((sysv_zone_t *) indbh->b_data)[i]) goto done; if ((indbh->b_count != 1) || (indtmp != *p)) { brelse(indbh); return 1; } *p = 0; *dirt = 1; sysv_free_block(sb,indblock); done: brelse(indbh); return retry; }
static int trunc_dindirect(struct inode * inode, int offset, unsigned long * p) { int i,tmp; struct buffer_head * dind_bh; unsigned long * dind; int retry = 0; #define DINDIRECT_BLOCK ((DIRECT_BLOCK-offset)>>8) tmp = *p; if (!tmp) return 0; dind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE); if (tmp != *p) { brelse(dind_bh); return 1; } if (!dind_bh) { *p = 0; return 0; } repeat: for (i = DINDIRECT_BLOCK ; i < 256 ; i ++) { if (i < 0) i = 0; if (i < DINDIRECT_BLOCK) goto repeat; dind = i+(unsigned long *) dind_bh->b_data; tmp = *dind; if (!tmp) continue; retry |= trunc_indirect(inode,offset+(i<<8),dind); mark_buffer_dirty(dind_bh, 1); } dind = (unsigned long *) dind_bh->b_data; for (i = 0; i < 256; i++) if (*(dind++)) break; if (i >= 256) if (dind_bh->b_count != 1) retry = 1; else { tmp = *p; *p = 0; inode->i_dirt = 1; ext_free_block(inode->i_sb,tmp); } brelse(dind_bh); return retry; }
void ext_truncate(struct inode * inode) { int retry; if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) return; while (1) { retry = trunc_direct(inode); 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_tindirect(inode); if (!retry) break; current->counter = 0; schedule(); } inode->i_mtime = inode->i_ctime = CURRENT_TIME; inode->i_dirt = 1; }