/* Sync one block full of indirect pointers and read it because we'll need it. */ static int sync_iblock (struct inode * inode, u32 * iblockp, int convert, struct buffer_head * *bh, int wait) { int rc; u32 tmp, block; *bh = NULL; block = tmp = *iblockp; if (convert) block = from_coh_ulong(block); if (!block) return 0; rc = sync_block (inode, iblockp, convert, wait); if (rc) return rc; *bh = sv_bread(inode->i_sb, inode->i_dev, block); if (tmp != *iblockp) { brelse(*bh); *bh = NULL; return 1; } if (!*bh) return -1; return 0; }
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 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; }