Index: linux-stage/fs/ext3/mballoc.c =================================================================== --- linux-stage.orig/fs/ext3/mballoc.c 2006-09-17 00:59:44.000000000 -0600 +++ linux-stage/fs/ext3/mballoc.c 2006-09-17 00:59:44.000000000 -0600 @@ -198,7 +198,8 @@ void ext3_mb_release_blocks(struct super_block *, int); void ext3_mb_poll_new_transaction(struct super_block *, handle_t *); void ext3_mb_free_committed_blocks(struct super_block *); - +unsigned long free_blks_after_init(struct super_block *, + struct ext3_group_desc *, int); #if BITS_PER_LONG == 64 #define mb_correct_addr_and_bit(bit,addr) \ { \ @@ -527,7 +528,12 @@ unlock_buffer(bh[i]); continue; } - + if (desc->bg_flags & EXT3_BG_BLOCK_UNINIT) { + init_block_bitmap(sb, bh[i], desc, first_group + i); + set_buffer_uptodate(bh[i]); + unlock_buffer(bh[i]); + continue; + } get_bh(bh[i]); bh[i]->b_end_io = end_buffer_read_sync; submit_bh(READ, bh[i]); @@ -1525,9 +1531,16 @@ mb_set_bits(bitmap_bh->b_data, ac.ac_b_ex.fe_start, ac.ac_b_ex.fe_len); spin_lock(sb_bgl_lock(sbi, ac.ac_b_ex.fe_group)); + if (gdp->bg_flags & EXT3_BG_BLOCK_UNINIT) { + gdp->bg_flags &= ~EXT3_BG_BLOCK_UNINIT; + gdp->bg_free_blocks_count = + cpu_to_le16(free_blks_after_init(sb, gdp, + ac.ac_b_ex.fe_group)); + } gdp->bg_free_blocks_count = cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - ac.ac_b_ex.fe_len); + gdp->bg_checksum = ext3_group_desc_csum(es, gdp, ac.ac_b_ex.fe_group); spin_unlock(sb_bgl_lock(sbi, ac.ac_b_ex.fe_group)); percpu_counter_mod(&sbi->s_freeblocks_counter, - ac.ac_b_ex.fe_len); @@ -2377,6 +2390,7 @@ spin_lock(sb_bgl_lock(sbi, block_group)); gdp->bg_free_blocks_count = cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) + count); + gdp->bg_checksum = ext3_group_desc_csum(es, gdp, block_group); spin_unlock(sb_bgl_lock(sbi, block_group)); percpu_counter_mod(&sbi->s_freeblocks_counter, count); Index: linux-stage/fs/ext3/ialloc.c =================================================================== --- linux-stage.orig/fs/ext3/ialloc.c 2006-09-17 00:59:44.000000000 -0600 +++ linux-stage/fs/ext3/ialloc.c 2006-09-17 00:59:44.000000000 -0600 @@ -23,7 +23,6 @@ #include #include #include - #include #include "xattr.h" @@ -59,8 +58,14 @@ desc = ext3_get_group_desc(sb, block_group, NULL); if (!desc) goto error_out; - - bh = sb_bread(sb, le32_to_cpu(desc->bg_inode_bitmap)); + if (desc->bg_flags & EXT3_BG_INODE_UNINIT) { + bh = sb_getblk(sb, le32_to_cpu(desc->bg_inode_bitmap)); + if (!buffer_uptodate(bh)) { + memset(bh->b_data,0,bh->b_size); + set_buffer_uptodate(bh); + } + } else + bh = sb_bread(sb, le32_to_cpu(desc->bg_inode_bitmap)); if (!bh) ext3_error(sb, "read_inode_bitmap", "Cannot read inode bitmap - " @@ -169,6 +174,8 @@ if (is_directory) gdp->bg_used_dirs_count = cpu_to_le16( le16_to_cpu(gdp->bg_used_dirs_count) - 1); + gdp->bg_checksum = ext3_group_desc_csum(es, gdp, + block_group); spin_unlock(sb_bgl_lock(sbi, block_group)); percpu_counter_inc(&sbi->s_freeinodes_counter); if (is_directory) @@ -202,7 +209,7 @@ static int find_group_dir(struct super_block *sb, struct inode *parent) { int ngroups = EXT3_SB(sb)->s_groups_count; - int freei, avefreei; + int freei, avefreei, freeb = 0, best_freeb = 0; struct ext3_group_desc *desc, *best_desc = NULL; struct buffer_head *bh; int group, best_group = -1; @@ -212,15 +219,17 @@ for (group = 0; group < ngroups; group++) { desc = ext3_get_group_desc (sb, group, &bh); - if (!desc || !desc->bg_free_inodes_count) + freei = EXT3_FREE_INODES_COUNT(desc); + freeb = EXT3_FREE_BLOCKS_COUNT(desc); + if (!desc || !freei) continue; - if (le16_to_cpu(desc->bg_free_inodes_count) < avefreei) + if (le16_to_cpu(freei) < avefreei) continue; - if (!best_desc || - (le16_to_cpu(desc->bg_free_blocks_count) > - le16_to_cpu(best_desc->bg_free_blocks_count))) { + if (!best_desc || + (le16_to_cpu(freeb) > le16_to_cpu(best_freeb))) { best_group = group; - best_desc = desc; + best_desc = desc; + best_freeb = freeb; } } return best_group; @@ -284,14 +293,16 @@ parent_group = (unsigned)group % ngroups; for (i = 0; i < ngroups; i++) { group = (parent_group + i) % ngroups; - desc = ext3_get_group_desc (sb, group, &bh); - if (!desc || !desc->bg_free_inodes_count) + desc = ext3_get_group_desc(sb, group, &bh); + freei = EXT3_FREE_INODES_COUNT(desc); + if (!desc || !freei) continue; if (le16_to_cpu(desc->bg_used_dirs_count) >= best_ndir) continue; - if (le16_to_cpu(desc->bg_free_inodes_count) < avefreei) + if (le16_to_cpu(freei) < avefreei) continue; - if (le16_to_cpu(desc->bg_free_blocks_count) < avefreeb) + freeb = EXT3_FREE_BLOCKS_COUNT(desc); + if (le16_to_cpu(freeb) < avefreeb) continue; best_group = group; best_ndir = le16_to_cpu(desc->bg_used_dirs_count); @@ -318,13 +329,15 @@ for (i = 0; i < ngroups; i++) { group = (parent_group + i) % ngroups; desc = ext3_get_group_desc (sb, group, &bh); - if (!desc || !desc->bg_free_inodes_count) + freei = EXT3_FREE_INODES_COUNT(desc); + freeb = EXT3_FREE_BLOCKS_COUNT(desc); + if (!desc || !freei) continue; if (le16_to_cpu(desc->bg_used_dirs_count) >= max_dirs) continue; - if (le16_to_cpu(desc->bg_free_inodes_count) < min_inodes) + if (le16_to_cpu(freei) < min_inodes) continue; - if (le16_to_cpu(desc->bg_free_blocks_count) < min_blocks) + if (le16_to_cpu(freeb) < min_blocks) continue; return group; } @@ -333,9 +346,10 @@ for (i = 0; i < ngroups; i++) { group = (parent_group + i) % ngroups; desc = ext3_get_group_desc (sb, group, &bh); - if (!desc || !desc->bg_free_inodes_count) + freei = EXT3_FREE_INODES_COUNT(desc); + if (!desc || !freei) continue; - if (le16_to_cpu(desc->bg_free_inodes_count) >= avefreei) + if (le16_to_cpu(freei) >= avefreei) return group; } @@ -362,6 +376,7 @@ int group, i; int best_group = -1; int avefreeb, freeb, best_group_freeb = 0; + int freei; /* * Try to place the inode in its parent directory @@ -392,11 +407,13 @@ if (group >= ngroups) group -= ngroups; desc = ext3_get_group_desc (sb, group, &bh); - if (!desc || !desc->bg_free_inodes_count) + freei = EXT3_FREE_INODES_COUNT(desc); + if (!desc || !freei) continue; if (!S_ISREG(mode)) return group; - if (le16_to_cpu(desc->bg_free_blocks_count) >= avefreeb) + freeb = EXT3_FREE_BLOCKS_COUNT(desc); + if (freeb >= avefreeb) return group; } @@ -413,9 +430,10 @@ if (++group >= ngroups) group = 0; desc = ext3_get_group_desc (sb, group, &bh); - if (!desc || !desc->bg_free_inodes_count) + freei = EXT3_FREE_INODES_COUNT(desc); + if (!desc || !freei) continue; - freeb = le16_to_cpu(desc->bg_free_blocks_count); + freeb = EXT3_FREE_BLOCKS_COUNT(desc); if (freeb > best_group_freeb) { best_group_freeb = freeb; best_group = group; @@ -453,6 +471,7 @@ int err = 0; struct inode *ret; int i; + int unused_flag = 0; /* Cannot create files in a deleted directory */ if (!dir || !dir->i_nlink) @@ -582,18 +601,33 @@ err = ext3_journal_get_write_access(handle, bh2); if (err) goto fail; spin_lock(sb_bgl_lock(sbi, group)); - gdp->bg_free_inodes_count = - cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) - 1); + if (gdp->bg_free_inodes_count == 0) { + if (gdp->bg_flags & EXT3_BG_INODE_UNINIT) { + gdp->bg_itable_unused = + cpu_to_le16(le16_to_cpu(es->s_inodes_per_group)); + gdp->bg_flags &= ~EXT3_BG_INODE_UNINIT; + } + /* If we didn't allocate from free initialized inodes, + * then we allocated from uninitialized inodes. In which + * case initialize one inode. */ + gdp->bg_itable_unused = + cpu_to_le16(le16_to_cpu(gdp->bg_itable_unused) - 1); + unused_flag = 1; + } else + gdp->bg_free_inodes_count = + cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) -1); if (S_ISDIR(mode)) { gdp->bg_used_dirs_count = cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) + 1); } + gdp->bg_checksum = ext3_group_desc_csum(es, gdp, group); spin_unlock(sb_bgl_lock(sbi, group)); BUFFER_TRACE(bh2, "call ext3_journal_dirty_metadata"); err = ext3_journal_dirty_metadata(handle, bh2); if (err) goto fail; - percpu_counter_dec(&sbi->s_freeinodes_counter); + if (!unused_flag) + percpu_counter_dec(&sbi->s_freeinodes_counter); if (S_ISDIR(mode)) percpu_counter_inc(&sbi->s_dirs_counter); sb->s_dirt = 1; Index: linux-stage/fs/ext3/balloc.c =================================================================== --- linux-stage.orig/fs/ext3/balloc.c 2006-09-17 00:59:44.000000000 -0600 +++ linux-stage/fs/ext3/balloc.c 2006-09-17 01:07:33.000000000 -0600 @@ -73,6 +73,88 @@ return desc + offset; } +unsigned long free_blks_after_init(struct super_block *sb, + struct ext3_group_desc *desc, + int block_group) +{ + struct ext3_sb_info *sbi = EXT3_SB(sb); + unsigned long blks; + unsigned long first_meta_bg; + int yes_super; + + first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg); + + /* Last and first groups are always initialized */ + blks = le32_to_cpu(EXT3_BLOCKS_PER_GROUP(sb)); + /* Account for for sb, gdt */ + yes_super = ext3_bg_has_super(sb, block_group); + if (yes_super) + blks--; + + if (!EXT3_HAS_RO_COMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_META_BG) || + block_group < first_meta_bg) { + if (yes_super) { + blks -= le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks); + blks -= ext3_bg_num_gdb(sb, block_group); + } + } else { /* For META_BG BLOCK GROUPS*/ + int group_rel = (block_group - first_meta_bg) % + EXT3_DESC_PER_BLOCK(sb); + if (group_rel == 0 || group_rel == 1 || + (group_rel == EXT3_DESC_PER_BLOCK(sb) - 1)) + blks--; + } + + /* Account for bitmaps and inode table */ + blks -= sbi->s_itb_per_group + 2; + return blks; +} + +/* Initializes an uninitialized block bitmap */ +void init_block_bitmap(struct super_block *sb, struct buffer_head *bh, + struct ext3_group_desc *desc, int block_group) +{ + unsigned startblk; + int bit, bit_max; + struct ext3_sb_info *sbi = EXT3_SB(sb); + unsigned long first_data_block, first_meta_bg; + + first_data_block = le32_to_cpu(sbi->s_es->s_first_data_block); + first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg); + memset(bh->b_data, 0, bh->b_size); + + /* Set bits for sb, gdt */ + startblk = block_group * EXT3_BLOCKS_PER_GROUP(sb) + + le32_to_cpu(sbi->s_es->s_first_data_block); + + bit = 0; + bit_max = ext3_bg_has_super(sb, block_group); + + if (!EXT3_HAS_RO_COMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_META_BG) || + block_group < first_meta_bg) { + if (bit_max) { + bit_max += ext3_bg_num_gdb(sb, block_group); + bit_max +=le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks); + } + } else { /* For META_BG_BLOCK_GROUPS */ + int group_rel = (block_group - first_meta_bg) % + EXT3_DESC_PER_BLOCK(sb); + if (group_rel == 0 || group_rel == 1 || + (group_rel == EXT3_DESC_PER_BLOCK(sb) - 1)) + bit_max += 1; + } + for (; bit < bit_max; bit++) + ext3_set_bit(bit, bh->b_data); + + /* Set bits for bitmaps and inode table */ + ext3_set_bit(le32_to_cpu(desc->bg_block_bitmap) - startblk, bh->b_data); + ext3_set_bit(le32_to_cpu(desc->bg_inode_bitmap) - startblk, bh->b_data); + bit_max = bit + sbi->s_itb_per_group; + for (bit = le32_to_cpu(desc->bg_inode_table) - startblk; + bit < bit_max; bit++) + ext3_set_bit(bit, bh->b_data); +} + /* * Read the bitmap for a given block_group, reading into the specified * slot in the superblock's bitmap cache. @@ -88,7 +170,18 @@ desc = ext3_get_group_desc (sb, block_group, NULL); if (!desc) goto error_out; - bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap)); + if (desc->bg_flags & EXT3_BG_BLOCK_UNINIT) { + bh = sb_getblk(sb, le32_to_cpu(desc->bg_block_bitmap)); + if (!buffer_uptodate(bh)) { + lock_buffer(bh); + if (!buffer_uptodate(bh)) { + init_block_bitmap(sb, bh, desc, block_group); + set_buffer_uptodate(bh); + } + unlock_buffer(bh); + } + } else + bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap)); if (!bh) ext3_error (sb, "read_block_bitmap", "Cannot read block bitmap - " @@ -465,6 +558,7 @@ desc->bg_free_blocks_count = cpu_to_le16(le16_to_cpu(desc->bg_free_blocks_count) + group_freed); + desc->bg_checksum = ext3_group_desc_csum(es, desc, block_group); spin_unlock(sb_bgl_lock(sbi, block_group)); percpu_counter_mod(&sbi->s_freeblocks_counter, count); @@ -1168,6 +1262,7 @@ static int goal_hits, goal_attempts; #endif unsigned long ngroups; + unsigned long free_blks; *errp = -ENOSPC; sb = inode->i_sb; @@ -1218,7 +1313,10 @@ goal_group = group_no; retry: - free_blocks = le16_to_cpu(gdp->bg_free_blocks_count); + if (gdp->bg_flags & EXT3_BG_BLOCK_UNINIT) + free_blocks = free_blks_after_init(sb, gdp, group_no); + else + free_blocks = EXT3_FREE_BLOCKS_COUNT(gdp); /* * if there is not enough free blocks to make a new resevation * turn off reservation for this allocation @@ -1257,7 +1355,11 @@ *errp = -EIO; goto out; } - free_blocks = le16_to_cpu(gdp->bg_free_blocks_count); + if (gdp->bg_flags & EXT3_BG_BLOCK_UNINIT) + free_blocks = cpu_to_le16(free_blks_after_init(sb, gdp, + group_no)); + else + free_blocks = EXT3_FREE_BLOCKS_COUNT(gdp); /* * skip this group if the number of * free blocks is less than half of the reservation @@ -1362,11 +1464,18 @@ ret_block, goal_hits, goal_attempts); spin_lock(sb_bgl_lock(sbi, group_no)); + free_blks = 0; + if (gdp->bg_flags & EXT3_BG_BLOCK_UNINIT) { + gdp->bg_flags &= ~EXT3_BG_BLOCK_UNINIT; + free_blks = cpu_to_le16(free_blks_after_init(sb, gdp,group_no)); + gdp->bg_free_blocks_count = free_blks; + } gdp->bg_free_blocks_count = cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - 1); + gdp->bg_checksum = ext3_group_desc_csum(es, gdp, group_no); spin_unlock(sb_bgl_lock(sbi, group_no)); percpu_counter_mod(&sbi->s_freeblocks_counter, -1); - + percpu_counter_mod(&sbi->s_freeblocks_counter, free_blks); BUFFER_TRACE(gdp_bh, "journal_dirty_metadata for group descriptor"); err = ext3_journal_dirty_metadata(handle, gdp_bh); if (!fatal) Index: linux-stage/fs/ext3/super.c =================================================================== --- linux-stage.orig/fs/ext3/super.c 2006-09-17 00:59:44.000000000 -0600 +++ linux-stage/fs/ext3/super.c 2006-09-17 01:13:43.000000000 -0600 @@ -1093,6 +1093,51 @@ return res; } +static __u16 crc16(__u16 crc, const u8 *buf, size_t len) +{ + __u16 tmp; + + while (len--) { + crc ^= *buf++; + crc ^= (u8)crc >> 4; + tmp = (u8)crc; + crc ^= (tmp ^ (tmp << 1)) << 4; + } + return crc; +} + +__u16 ext3_group_desc_csum(struct ext3_super_block *sb, + struct ext3_group_desc *desc, __u32 group) +{ + __u16 crc = 0; + + if (sb->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) { + int offset = offsetof(struct ext3_group_desc, bg_checksum); + + group = cpu_to_le32(group); + crc = crc16(~0, (__u8 *)&group, sizeof(group)); + crc = crc16(crc, (__u8 *)desc, offset); + offset += sizeof(desc->bg_checksum); /* skip checksum */ + BUG_ON(offset != sizeof(*desc)); /* XXX handle s_desc_size */ + /* + if (offset < sb->s_desc_size) { + crc = crc16(crc, (__u8 *)desc + offset, + sb->s_desc_size - offset); + */ + } + + return cpu_to_le16(crc); +} + +int ext3_group_desc_csum_verify(struct ext3_super_block *sb, + struct ext3_group_desc *desc, __u32 group) +{ + if (desc->bg_checksum != ext3_group_desc_csum(sb, desc, group)) + return 0; + + return 1; +} + /* Called at mount-time, super-block is locked */ static int ext3_check_descriptors (struct super_block * sb) { @@ -1142,6 +1187,13 @@ le32_to_cpu(gdp->bg_inode_table)); return 0; } + if (!ext3_group_desc_csum_verify(sb, gdp, i)) { + ext3_error(sb, __FUNCTION__, + "Checksum for group %d failed (%u != %u)\n", + i, ext3_group_desc_csum(sb, gdp, i), + gdp->bg_checksum); + return 0; + } block += EXT3_BLOCKS_PER_GROUP(sb); gdp++; } Index: linux-stage/fs/ext3/resize.c =================================================================== --- linux-stage.orig/fs/ext3/resize.c 2006-09-17 00:59:44.000000000 -0600 +++ linux-stage/fs/ext3/resize.c 2006-09-17 00:59:44.000000000 -0600 @@ -19,7 +19,6 @@ #include #include - #define outside(b, first, last) ((b) < (first) || (b) >= (last)) #define inside(b, first, last) ((b) >= (first) && (b) < (last)) @@ -807,6 +806,7 @@ gdp->bg_inode_table = cpu_to_le32(input->inode_table); gdp->bg_free_blocks_count = cpu_to_le16(input->free_blocks_count); gdp->bg_free_inodes_count = cpu_to_le16(EXT3_INODES_PER_GROUP(sb)); + gdp->bg_checksum = ext3_group_desc_csum(es, gdp, input->group); /* * Make the new blocks and inodes valid next. We do this before Index: linux-stage/include/linux/ext3_fs.h =================================================================== --- linux-stage.orig/include/linux/ext3_fs.h 2006-09-17 00:59:44.000000000 -0600 +++ linux-stage/include/linux/ext3_fs.h 2006-09-17 01:02:00.000000000 -0600 @@ -118,6 +118,16 @@ (s)->s_first_ino) #endif +//Macro-instructions used to calculate Free inodes and blocks count + +#define EXT3_FREE_INODES_COUNT(desc) (desc->bg_flags &EXT3_BG_INODE_UNINIT)?\ + EXT3_INODES_PER_GROUP(sb) : \ + (desc->bg_free_inodes_count + \ + desc->bg_itable_unused) +#define EXT3_FREE_BLOCKS_COUNT(desc) (desc->bg_flags &EXT3_BG_BLOCK_UNINIT)?\ + EXT3_BLOCKS_PER_GROUP(sb) : \ + (desc->bg_free_blocks_count) + /* * Macro-instructions used to manage fragments */ @@ -137,16 +147,21 @@ */ struct ext3_group_desc { - __le32 bg_block_bitmap; /* Blocks bitmap block */ - __le32 bg_inode_bitmap; /* Inodes bitmap block */ + __le32 bg_block_bitmap; /* Blocks bitmap block */ + __le32 bg_inode_bitmap; /* Inodes bitmap block */ __le32 bg_inode_table; /* Inodes table block */ __le16 bg_free_blocks_count; /* Free blocks count */ __le16 bg_free_inodes_count; /* Free inodes count */ __le16 bg_used_dirs_count; /* Directories count */ - __u16 bg_pad; - __le32 bg_reserved[3]; + __le16 bg_flags; + __le32 bg_reserved[2]; + __le16 bg_itable_unused; /*Unused inodes count*/ + __le16 bg_checksum; }; +#define EXT3_BG_INODE_UNINIT 0x0001 /* Inode table/bitmap not initialized */ +#define EXT3_BG_BLOCK_UNINIT 0x0002 /* Block bitmap not initialized */ + /* * Macro-instructions used to manage group descriptors */ @@ -565,6 +580,7 @@ #define EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 #define EXT3_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 #define EXT3_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 +#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010 /* Descriptor checksum */ #define EXT3_FEATURE_INCOMPAT_COMPRESSION 0x0001 #define EXT3_FEATURE_INCOMPAT_FILETYPE 0x0002 @@ -580,7 +596,8 @@ EXT3_FEATURE_INCOMPAT_EXTENTS) #define EXT3_FEATURE_RO_COMPAT_SUPP (EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER| \ EXT3_FEATURE_RO_COMPAT_LARGE_FILE| \ - EXT3_FEATURE_RO_COMPAT_BTREE_DIR) + EXT3_FEATURE_RO_COMPAT_BTREE_DIR|\ + EXT4_FEATURE_RO_COMPAT_GDT_CSUM) /* * Default values for user and/or group using reserved blocks @@ -830,6 +847,10 @@ extern void ext3_warning (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4))); extern void ext3_update_dynamic_rev (struct super_block *sb); +extern __u16 ext3_group_desc_csum(struct ext3_super_block *sb, + struct ext3_group_desc *desc, __u32 group); +extern int ext2fs_group_desc_csum_verify(struct ext2_super_block *sb, + struct ext2_group_desc *desc, __u32 group); #define ext3_std_error(sb, errno) \ do { \