/* Leave at most `blocks' blocks out of an indirect block whose number is * from_coh_ulong(*p) if convert=1, *p if convert=0. */ static int coh_trunc_indirect (struct inode * inode, unsigned long blocks, unsigned long * p, int convert, unsigned char * dirt) { struct super_block * sb = inode->i_sb; unsigned long tmp, block, indblock; struct buffer_head * bh; char * bh_data; unsigned long i; sysv_zone_t * ind; if (blocks >= sb->sv_ind_per_block) return 0; block = tmp = *p; if (convert) block = from_coh_ulong(block); if (!block) return 0; bh = sysv_bread(sb,inode->i_dev,block,&bh_data); if (tmp != *p) { brelse(bh); return 1; } if (!bh) { *p = 0; *dirt = 1; return 0; } for (i = blocks; i < sb->sv_ind_per_block; i++) { ind = &((sysv_zone_t *) bh_data)[i]; indblock = *ind; if (sb->sv_convert) indblock = from_coh_ulong(indblock); if (!indblock) continue; *ind = 0; mark_buffer_dirty(bh, 1); sysv_free_block(sb,indblock); } for (i = 0; i < sb->sv_ind_per_block; i++) if (((sysv_zone_t *) bh_data)[i]) goto done; if (tmp != *p) { brelse(bh); return 1; } *p = 0; *dirt = 1; sysv_free_block(sb,block); done: brelse(bh); return 0; }
static int trunc_direct(struct inode * inode) { struct super_block * sb; unsigned int i; u32 * p; u32 block; struct buffer_head * bh; int retry = 0; sb = inode->i_sb; repeat: for (i = ((unsigned long) inode->i_size + sb->sv_block_size_1) >> sb->sv_block_size_bits; i < 10; i++) { p = inode->u.sysv_i.i_data + i; block = *p; if (!block) continue; bh = sv_get_hash_table(sb, inode->i_dev, block); if ((i << sb->sv_block_size_bits) < inode->i_size) { brelse(bh); goto repeat; } if ((bh && bh->b_count != 1) || (block != *p)) { retry = 1; brelse(bh); continue; } *p = 0; mark_inode_dirty(inode); brelse(bh); sysv_free_block(sb,block); } return retry; }
static int trunc_direct(struct inode * inode) { struct super_block * sb; unsigned int i; unsigned long * p; unsigned long block; struct buffer_head * bh; int retry = 0; sb = inode->i_sb; repeat: for (i = ((unsigned long) inode->i_size + BLOCK_SIZE-1) / BLOCK_SIZE; i < 10; i++) { p = inode->u.sysv_i.i_data + i; block = *p; if (!block) continue; bh = get_hash_table(inode->i_dev,block+sb->sv_block_base,BLOCK_SIZE); if (i*BLOCK_SIZE < inode->i_size) { brelse(bh); goto repeat; } if ((bh && bh->b_count != 1) || (block != *p)) { retry = 1; brelse(bh); continue; } *p = 0; inode->i_dirt = 1; brelse(bh); sysv_free_block(sb,block); } return retry; }
static int trunc_tindirect(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_2_block_size_1) >> sb->sv_ind_per_block_2_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_dindirect(inode,offset+(i<<sb->sv_ind_per_block_2_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 struct buffer_head * block_getblk(struct inode * inode, struct buffer_head * bh, int nr, int create, char * *start) { struct super_block *sb; unsigned long tmp, block; sysv_zone_t *p; struct buffer_head * result; if (!bh) return NULL; if (!bh->b_uptodate) { ll_rw_block(READ, 1, &bh); wait_on_buffer(bh); if (!bh->b_uptodate) { brelse(bh); return NULL; } } sb = inode->i_sb; p = nr + (sysv_zone_t *) *start; repeat: block = tmp = *p; if (sb->sv_convert) block = from_coh_ulong(block); if (tmp) { result = getblk(bh->b_dev, (block >> sb->sv_block_size_ratio_bits) + sb->sv_block_base, BLOCK_SIZE); if (tmp == *p) { brelse(bh); *start = result->b_data + ((block & sb->sv_block_size_ratio_1) << sb->sv_block_size_bits); return result; } brelse(result); goto repeat; } if (!create) { brelse(bh); return NULL; } block = sysv_new_block(sb); if (!block) { brelse(bh); return NULL; } result = getblk(bh->b_dev, (block >> sb->sv_block_size_ratio_bits) + sb->sv_block_base, BLOCK_SIZE); if (*p) { sysv_free_block(sb,block); brelse(result); goto repeat; } *p = (sb->sv_convert ? to_coh_ulong(block) : block); mark_buffer_dirty(bh, 1); brelse(bh); *start = result->b_data + ((block & sb->sv_block_size_ratio_1) << sb->sv_block_size_bits); return result; }
static int trunc_tindirect(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*IND_PER_BLOCK*BLOCK_SIZE-1) / (IND_PER_BLOCK*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_dindirect(inode,offset+i*IND_PER_BLOCK*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; }
/* Leave at most `blocks' blocks out of an double indirect block whose number is * from_coh_ulong(*p) if convert=1, *p if convert=0. */ static int coh_trunc_dindirect (struct inode * inode, unsigned long blocks, unsigned long * p, int convert, unsigned char * dirt) { struct super_block * sb = inode->i_sb; unsigned long tmp, block, dindblock; struct buffer_head * bh; char * bh_data; unsigned long i, j; sysv_zone_t * dind; int retry = 0; if (blocks >= sb->sv_ind_per_block_2) return 0; block = tmp = *p; if (convert) block = from_coh_ulong(block); if (!block) return 0; bh = sysv_bread(sb,inode->i_dev,block,&bh_data); if (tmp != *p) { brelse(bh); return 1; } if (!bh) { *p = 0; *dirt = 1; return 0; } for (i = blocks >> sb->sv_ind_per_block_bits, j = blocks & sb->sv_ind_per_block_1; i < sb->sv_ind_per_block; i++, j = 0) { /* j = max(blocks-i*ind_per_block,0) */ dind = &((sysv_zone_t *) bh_data)[i]; dindblock = *dind; if (sb->sv_convert) dindblock = from_coh_ulong(dindblock); if (!dindblock) continue; retry |= coh_trunc_indirect(inode,j,dind,sb->sv_convert,&bh->b_dirt); } for (i = 0; i < sb->sv_ind_per_block; i++) if (((sysv_zone_t *) bh_data)[i]) goto done; if (tmp != *p) { brelse(bh); return 1; } *p = 0; *dirt = 1; sysv_free_block(sb,block); done: brelse(bh); return retry; }
/* Leave at most `blocks' direct blocks. */ static int coh_trunc_direct (struct inode * inode, unsigned long blocks) { unsigned int i; unsigned long * p; unsigned long block; for (i = blocks; i < 10 ; i++) { p = &inode->u.sysv_i.i_data[i]; block = *p; if (!block) continue; *p = 0; inode->i_dirt = 1; sysv_free_block(inode->i_sb,block); } return 0; }
static struct buffer_head * inode_getblk(struct inode * inode, int nr, int create, char * *start) { struct super_block *sb; unsigned long tmp; unsigned long *p; struct buffer_head * result; sb = inode->i_sb; p = inode->u.sysv_i.i_data + nr; repeat: tmp = *p; if (tmp) { result = getblk(inode->i_dev, (tmp >> sb->sv_block_size_ratio_bits) + sb->sv_block_base, BLOCK_SIZE); if (tmp == *p) { *start = result->b_data + ((tmp & sb->sv_block_size_ratio_1) << sb->sv_block_size_bits); return result; } brelse(result); goto repeat; } if (!create) return NULL; tmp = sysv_new_block(sb); if (!tmp) return NULL; result = getblk(inode->i_dev, (tmp >> sb->sv_block_size_ratio_bits) + sb->sv_block_base, BLOCK_SIZE); if (*p) { sysv_free_block(sb,tmp); brelse(result); goto repeat; } *p = tmp; inode->i_ctime = CURRENT_TIME; inode->i_dirt = 1; *start = result->b_data + ((tmp & sb->sv_block_size_ratio_1) << sb->sv_block_size_bits); return result; }
static int trunc_indirect(struct inode * inode, unsigned long offset, sysv_zone_t * 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; struct buffer_head * bh; 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; } repeat: if (inode->i_size < offset) i = 0; else i = (inode->i_size - offset + sb->sv_block_size_1) >> sb->sv_block_size_bits; for (; i < sb->sv_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; bh = sv_get_hash_table(sb, inode->i_dev, block); if ((i << sb->sv_block_size_bits) + offset < inode->i_size) { brelse(bh); goto repeat; } if ((bh && bh->b_count != 1) || (tmp != *ind)) { retry = 1; brelse(bh); continue; } *ind = 0; mark_buffer_dirty(indbh, 1); brelse(bh); sysv_free_block(sb,block); } 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; }