int hfsplus_file_extend(struct inode *inode) { struct super_block *sb = inode->i_sb; u32 start, len, goal; int res; if (HFSPLUS_SB(sb).alloc_file->i_size * 8 < HFSPLUS_SB(sb).total_blocks - HFSPLUS_SB(sb).free_blocks + 8) { // extend alloc file printk("extend alloc file! (%Lu,%u,%u)\n", HFSPLUS_SB(sb).alloc_file->i_size * 8, HFSPLUS_SB(sb).total_blocks, HFSPLUS_SB(sb).free_blocks); return -ENOSPC; //BUG(); } down(&HFSPLUS_I(inode).extents_lock); if (HFSPLUS_I(inode).alloc_blocks == HFSPLUS_I(inode).first_blocks) goal = hfsplus_ext_lastblock(HFSPLUS_I(inode).first_extents); else { res = hfsplus_ext_read_extent(inode, HFSPLUS_I(inode).alloc_blocks); if (res) goto out; goal = hfsplus_ext_lastblock(HFSPLUS_I(inode).cached_extents); } len = HFSPLUS_I(inode).clump_blocks; start = hfsplus_block_allocate(sb, HFSPLUS_SB(sb).total_blocks, goal, &len); if (start >= HFSPLUS_SB(sb).total_blocks) { start = hfsplus_block_allocate(sb, goal, 0, &len); if (start >= goal) { res = -ENOSPC; goto out; } } dprint(DBG_EXTENT, "extend %lu: %u,%u\n", inode->i_ino, start, len); if (HFSPLUS_I(inode).alloc_blocks <= HFSPLUS_I(inode).first_blocks) { if (!HFSPLUS_I(inode).first_blocks) { dprint(DBG_EXTENT, "first extents\n"); /* no extents yet */ HFSPLUS_I(inode).first_extents[0].start_block = cpu_to_be32(start); HFSPLUS_I(inode).first_extents[0].block_count = cpu_to_be32(len); res = 0; } else { /* try to append to extents in inode */ res = hfsplus_add_extent(HFSPLUS_I(inode).first_extents, HFSPLUS_I(inode).alloc_blocks, start, len); if (res == -ENOSPC) goto insert_extent; } if (!res) { hfsplus_dump_extent(HFSPLUS_I(inode).first_extents); HFSPLUS_I(inode).first_blocks += len; } } else { res = hfsplus_add_extent(HFSPLUS_I(inode).cached_extents, HFSPLUS_I(inode).alloc_blocks - HFSPLUS_I(inode).cached_start, start, len); if (!res) { hfsplus_dump_extent(HFSPLUS_I(inode).cached_extents); HFSPLUS_I(inode).flags |= HFSPLUS_FLG_EXT_DIRTY; HFSPLUS_I(inode).cached_blocks += len; } else if (res == -ENOSPC) goto insert_extent; } out: up(&HFSPLUS_I(inode).extents_lock); if (!res) { HFSPLUS_I(inode).alloc_blocks += len; mark_inode_dirty(inode); } return res; insert_extent: dprint(DBG_EXTENT, "insert new extent\n"); hfsplus_ext_write_extent(inode); memset(HFSPLUS_I(inode).cached_extents, 0, sizeof(hfsplus_extent_rec)); HFSPLUS_I(inode).cached_extents[0].start_block = cpu_to_be32(start); HFSPLUS_I(inode).cached_extents[0].block_count = cpu_to_be32(len); hfsplus_dump_extent(HFSPLUS_I(inode).cached_extents); HFSPLUS_I(inode).flags |= HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW; HFSPLUS_I(inode).cached_start = HFSPLUS_I(inode).alloc_blocks; HFSPLUS_I(inode).cached_blocks = len; res = 0; goto out; }
int hfsplus_file_extend(struct inode *inode, bool zeroout) { struct super_block *sb = inode->i_sb; struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); struct hfsplus_inode_info *hip = HFSPLUS_I(inode); u32 start, len, goal; int res; if (sbi->alloc_file->i_size * 8 < sbi->total_blocks - sbi->free_blocks + 8) { /* extend alloc file */ pr_err("extend alloc file! (%llu,%u,%u)\n", sbi->alloc_file->i_size * 8, sbi->total_blocks, sbi->free_blocks); return -ENOSPC; } mutex_lock(&hip->extents_lock); if (hip->alloc_blocks == hip->first_blocks) goal = hfsplus_ext_lastblock(hip->first_extents); else { res = hfsplus_ext_read_extent(inode, hip->alloc_blocks); if (res) goto out; goal = hfsplus_ext_lastblock(hip->cached_extents); } len = hip->clump_blocks; start = hfsplus_block_allocate(sb, sbi->total_blocks, goal, &len); if (start >= sbi->total_blocks) { start = hfsplus_block_allocate(sb, goal, 0, &len); if (start >= goal) { res = -ENOSPC; goto out; } } if (zeroout) { res = sb_issue_zeroout(sb, start, len, GFP_NOFS); if (res) goto out; } hfs_dbg(EXTENT, "extend %lu: %u,%u\n", inode->i_ino, start, len); if (hip->alloc_blocks <= hip->first_blocks) { if (!hip->first_blocks) { hfs_dbg(EXTENT, "first extents\n"); /* no extents yet */ hip->first_extents[0].start_block = cpu_to_be32(start); hip->first_extents[0].block_count = cpu_to_be32(len); res = 0; } else { /* try to append to extents in inode */ res = hfsplus_add_extent(hip->first_extents, hip->alloc_blocks, start, len); if (res == -ENOSPC) goto insert_extent; } if (!res) { hfsplus_dump_extent(hip->first_extents); hip->first_blocks += len; } } else { res = hfsplus_add_extent(hip->cached_extents, hip->alloc_blocks - hip->cached_start, start, len); if (!res) { hfsplus_dump_extent(hip->cached_extents); hip->extent_state |= HFSPLUS_EXT_DIRTY; hip->cached_blocks += len; } else if (res == -ENOSPC) goto insert_extent; } out: if (!res) { hip->alloc_blocks += len; mutex_unlock(&hip->extents_lock); hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ALLOC_DIRTY); return 0; } mutex_unlock(&hip->extents_lock); return res; insert_extent: hfs_dbg(EXTENT, "insert new extent\n"); res = hfsplus_ext_write_extent_locked(inode); if (res) goto out; memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec)); hip->cached_extents[0].start_block = cpu_to_be32(start); hip->cached_extents[0].block_count = cpu_to_be32(len); hfsplus_dump_extent(hip->cached_extents); hip->extent_state |= HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW; hip->cached_start = hip->alloc_blocks; hip->cached_blocks = len; res = 0; goto out; }