void ocfs2_la_set_sizes(struct ocfs2_super *osb, int requested_mb) { struct super_block *sb = osb->sb; unsigned int la_default_mb = ocfs2_la_default_mb(osb); unsigned int la_max_mb; la_max_mb = ocfs2_clusters_to_megabytes(sb, ocfs2_local_alloc_size(sb) * 8); trace_ocfs2_la_set_sizes(requested_mb, la_max_mb, la_default_mb); if (requested_mb == -1) { /* No user request - use defaults */ osb->local_alloc_default_bits = ocfs2_megabytes_to_clusters(sb, la_default_mb); } else if (requested_mb > la_max_mb) { /* Request is too big, we give the maximum available */ osb->local_alloc_default_bits = ocfs2_megabytes_to_clusters(sb, la_max_mb); } else { osb->local_alloc_default_bits = ocfs2_megabytes_to_clusters(sb, requested_mb); } osb->local_alloc_bits = osb->local_alloc_default_bits; }
void ocfs2_la_set_sizes(struct ocfs2_super *osb, int requested_mb) { struct super_block *sb = osb->sb; unsigned int la_default_mb = ocfs2_la_default_mb(osb); unsigned int la_max_mb; la_max_mb = ocfs2_clusters_to_megabytes(sb, ocfs2_local_alloc_size(sb) * 8); trace_ocfs2_la_set_sizes(requested_mb, la_max_mb, la_default_mb); if (requested_mb == -1) { /* */ osb->local_alloc_default_bits = ocfs2_megabytes_to_clusters(sb, la_default_mb); } else if (requested_mb > la_max_mb) { /* */ osb->local_alloc_default_bits = ocfs2_megabytes_to_clusters(sb, la_max_mb); } else { osb->local_alloc_default_bits = ocfs2_megabytes_to_clusters(sb, requested_mb); } osb->local_alloc_bits = osb->local_alloc_default_bits; }
int ocfs2_load_local_alloc(struct ocfs2_super *osb) { int status = 0; struct ocfs2_dinode *alloc = NULL; struct buffer_head *alloc_bh = NULL; u32 num_used; struct inode *inode = NULL; struct ocfs2_local_alloc *la; if (osb->local_alloc_bits == 0) goto bail; if (osb->local_alloc_bits >= osb->bitmap_cpg) { mlog(ML_NOTICE, "Requested local alloc window %d is larger " "than max possible %u. Using defaults.\n", osb->local_alloc_bits, (osb->bitmap_cpg - 1)); osb->local_alloc_bits = ocfs2_megabytes_to_clusters(osb->sb, ocfs2_la_default_mb(osb)); } /* read the alloc off disk */ inode = ocfs2_get_system_file_inode(osb, LOCAL_ALLOC_SYSTEM_INODE, osb->slot_num); if (!inode) { status = -EINVAL; mlog_errno(status); goto bail; } status = ocfs2_read_inode_block_full(inode, &alloc_bh, OCFS2_BH_IGNORE_CACHE); if (status < 0) { mlog_errno(status); goto bail; } alloc = (struct ocfs2_dinode *) alloc_bh->b_data; la = OCFS2_LOCAL_ALLOC(alloc); if (!(le32_to_cpu(alloc->i_flags) & (OCFS2_LOCAL_ALLOC_FL|OCFS2_BITMAP_FL))) { mlog(ML_ERROR, "Invalid local alloc inode, %llu\n", (unsigned long long)OCFS2_I(inode)->ip_blkno); status = -EINVAL; goto bail; } if ((la->la_size == 0) || (le16_to_cpu(la->la_size) > ocfs2_local_alloc_size(inode->i_sb))) { mlog(ML_ERROR, "Local alloc size is invalid (la_size = %u)\n", le16_to_cpu(la->la_size)); status = -EINVAL; goto bail; } /* do a little verification. */ num_used = ocfs2_local_alloc_count_bits(alloc); /* hopefully the local alloc has always been recovered before * we load it. */ if (num_used || alloc->id1.bitmap1.i_used || alloc->id1.bitmap1.i_total || la->la_bm_off) mlog(ML_ERROR, "Local alloc hasn't been recovered!\n" "found = %u, set = %u, taken = %u, off = %u\n", num_used, le32_to_cpu(alloc->id1.bitmap1.i_used), le32_to_cpu(alloc->id1.bitmap1.i_total), OCFS2_LOCAL_ALLOC(alloc)->la_bm_off); osb->local_alloc_bh = alloc_bh; osb->local_alloc_state = OCFS2_LA_ENABLED; bail: if (status < 0) brelse(alloc_bh); iput(inode); trace_ocfs2_load_local_alloc(osb->local_alloc_bits); if (status) mlog_errno(status); return status; }
unsigned int ocfs2_la_default_mb(struct ocfs2_super *osb) { unsigned int la_mb; unsigned int gd_mb; unsigned int la_max_mb; unsigned int megs_per_slot; struct super_block *sb = osb->sb; gd_mb = ocfs2_clusters_to_megabytes(osb->sb, 8 * ocfs2_group_bitmap_size(sb, 0, osb->s_feature_incompat)); /* * This takes care of files systems with very small group * descriptors - 512 byte blocksize at cluster sizes lower * than 16K and also 1k blocksize with 4k cluster size. */ if ((sb->s_blocksize == 512 && osb->s_clustersize <= 8192) || (sb->s_blocksize == 1024 && osb->s_clustersize == 4096)) return OCFS2_LA_OLD_DEFAULT; /* * Leave enough room for some block groups and make the final * value we work from a multiple of 4. */ gd_mb -= 16; gd_mb &= 0xFFFFFFFB; la_mb = gd_mb; /* * Keep window sizes down to a reasonable default */ if (la_mb > OCFS2_LA_MAX_DEFAULT_MB) { /* * Some clustersize / blocksize combinations will have * given us a larger than OCFS2_LA_MAX_DEFAULT_MB * default size, but get poor distribution when * limited to exactly 256 megabytes. * * As an example, 16K clustersize at 4K blocksize * gives us a cluster group size of 504M. Paring the * local alloc size down to 256 however, would give us * only one window and around 200MB left in the * cluster group. Instead, find the first size below * 256 which would give us an even distribution. * * Larger cluster group sizes actually work out pretty * well when pared to 256, so we don't have to do this * for any group that fits more than two * OCFS2_LA_MAX_DEFAULT_MB windows. */ if (gd_mb > (2 * OCFS2_LA_MAX_DEFAULT_MB)) la_mb = 256; else { unsigned int gd_mult = gd_mb; while (gd_mult > 256) gd_mult = gd_mult >> 1; la_mb = gd_mult; } } megs_per_slot = osb->osb_clusters_at_boot / osb->max_slots; megs_per_slot = ocfs2_clusters_to_megabytes(osb->sb, megs_per_slot); /* Too many nodes, too few disk clusters. */ if (megs_per_slot < la_mb) la_mb = megs_per_slot; /* We can't store more bits than we can in a block. */ la_max_mb = ocfs2_clusters_to_megabytes(osb->sb, ocfs2_local_alloc_size(sb) * 8); if (la_mb > la_max_mb) la_mb = la_max_mb; return la_mb; }
static void damage_local_alloc(ocfs2_filesys *fs, uint64_t blkno, enum fsck_type type) { errcode_t ret; char *buf = NULL; struct ocfs2_dinode *di; struct ocfs2_local_alloc *la; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) FSWRK_COM_FATAL(progname, ret); ret = ocfs2_read_inode(fs, blkno, buf); if (ret) FSWRK_COM_FATAL(progname, ret); di = (struct ocfs2_dinode *)buf; if (!(di->i_flags & OCFS2_VALID_FL)) FSWRK_FATAL("not a file"); if (!(di->i_flags & OCFS2_LOCAL_ALLOC_FL)) FSWRK_FATAL("not a local alloc file"); la = &(di->id2.i_lab); /* For LALLOC_BM_OVERRUN, LALLOC_BM_STRADDLE,LALLOC_BM_SIZE, * LALLOC_USED_OVERRUN, LALLOC_CLEAR, i_total must be greater than 0. * So check it first. */ if (type == LALLOC_BM_OVERRUN || type == LALLOC_BM_STRADDLE || type == LALLOC_BM_SIZE || type == LALLOC_USED_OVERRUN) if (di->id1.bitmap1.i_total == 0) { FSWRK_WARN("local inode#%"PRIu64" is empty, so can't" "corrupt it for type[%d]\n", blkno, type); goto bail; } switch (type) { case LALLOC_SIZE: case LALLOC_CLEAR: if (type == LALLOC_SIZE) fprintf(stdout, "LALLOC_SIZE: "); else fprintf(stdout, "LALLOC_CLEAR: "); fprintf(stdout, "Corrupt local alloc inode#%"PRIu64 ", change size from %u to %u\n", blkno, la->la_size, (ocfs2_local_alloc_size(fs->fs_blocksize) + 10)); la->la_size = ocfs2_local_alloc_size(fs->fs_blocksize) + 10; break; case LALLOC_NZ_USED: di->id1.bitmap1.i_total = 0; di->id1.bitmap1.i_used = 10; fprintf(stdout, "LALLOC_NZ_USED: " "Corrupt local alloc inode#%"PRIu64", total = %d " " used = %d\n",blkno, di->id1.bitmap1.i_total, di->id1.bitmap1.i_used); break; case LALLOC_NZ_BM: di->id1.bitmap1.i_total = 0; la->la_bm_off = 100; fprintf(stdout, "LALLOC_NZ_BM: " "Corrupt local alloc inode#%"PRIu64", total = %d " " la_bm_off = %d\n",blkno, di->id1.bitmap1.i_total, la->la_bm_off); break; case LALLOC_BM_OVERRUN: case LALLOC_BM_STRADDLE: la->la_bm_off = fs->fs_clusters + 10; if (type == LALLOC_BM_OVERRUN) fprintf(stdout, "LALLOC_BM_OVERRUN: "); else fprintf(stdout, "LALLOC_BM_STRADDLE: "); fprintf(stdout, "Corrupt local alloc inode#%"PRIu64 ", la_bm_off =%u\n", blkno, la->la_bm_off); break; case LALLOC_BM_SIZE: fprintf(stdout, "LALLOC_SIZE: " "Corrupt local alloc inode#%"PRIu64", change i_total" " from %u to %u\n", blkno, di->id1.bitmap1.i_total, (la->la_size * 8 + 10)); di->id1.bitmap1.i_total = la->la_size * 8 + 10; break; case LALLOC_USED_OVERRUN: fprintf(stdout, "LALLOC_USED_OVERRUN: " "Corrupt local alloc inode#%"PRIu64", change i_used" " from %u to %u\n", blkno, di->id1.bitmap1.i_used, (di->id1.bitmap1.i_total + 10)); di->id1.bitmap1.i_used = di->id1.bitmap1.i_total + 10; break; default: FSWRK_FATAL("Unknown type = %d", type); } ret = ocfs2_write_inode(fs, blkno, buf); if (ret) FSWRK_COM_FATAL(progname, ret); bail: if (buf) ocfs2_free(&buf); return; }
unsigned int ocfs2_la_default_mb(struct ocfs2_super *osb) { unsigned int la_mb; unsigned int gd_mb; unsigned int la_max_mb; unsigned int megs_per_slot; struct super_block *sb = osb->sb; gd_mb = ocfs2_clusters_to_megabytes(osb->sb, 8 * ocfs2_group_bitmap_size(sb, 0, osb->s_feature_incompat)); /* */ if ((sb->s_blocksize == 512 && osb->s_clustersize <= 8192) || (sb->s_blocksize == 1024 && osb->s_clustersize == 4096)) return OCFS2_LA_OLD_DEFAULT; /* */ gd_mb -= 16; gd_mb &= 0xFFFFFFFB; la_mb = gd_mb; /* */ if (la_mb > OCFS2_LA_MAX_DEFAULT_MB) { /* */ if (gd_mb > (2 * OCFS2_LA_MAX_DEFAULT_MB)) la_mb = 256; else { unsigned int gd_mult = gd_mb; while (gd_mult > 256) gd_mult = gd_mult >> 1; la_mb = gd_mult; } } megs_per_slot = osb->osb_clusters_at_boot / osb->max_slots; megs_per_slot = ocfs2_clusters_to_megabytes(osb->sb, megs_per_slot); /* */ if (megs_per_slot < la_mb) la_mb = megs_per_slot; /* */ la_max_mb = ocfs2_clusters_to_megabytes(osb->sb, ocfs2_local_alloc_size(sb) * 8); if (la_mb > la_max_mb) la_mb = la_max_mb; return la_mb; }
int ocfs2_load_local_alloc(struct ocfs2_super *osb) { int status = 0; struct ocfs2_dinode *alloc = NULL; struct buffer_head *alloc_bh = NULL; u32 num_used; struct inode *inode = NULL; struct ocfs2_local_alloc *la; mlog_entry_void(); /* read the alloc off disk */ inode = ocfs2_get_system_file_inode(osb, LOCAL_ALLOC_SYSTEM_INODE, osb->slot_num); if (!inode) { status = -EINVAL; mlog_errno(status); goto bail; } status = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno, &alloc_bh, 0, inode); if (status < 0) { mlog_errno(status); goto bail; } alloc = (struct ocfs2_dinode *) alloc_bh->b_data; la = OCFS2_LOCAL_ALLOC(alloc); if (!(le32_to_cpu(alloc->i_flags) & (OCFS2_LOCAL_ALLOC_FL|OCFS2_BITMAP_FL))) { mlog(ML_ERROR, "Invalid local alloc inode, %"MLFu64"\n", OCFS2_I(inode)->ip_blkno); status = -EINVAL; goto bail; } if ((la->la_size == 0) || (le16_to_cpu(la->la_size) > ocfs2_local_alloc_size(inode->i_sb))) { mlog(ML_ERROR, "Local alloc size is invalid (la_size = %u)\n", le16_to_cpu(la->la_size)); status = -EINVAL; goto bail; } /* do a little verification. */ num_used = ocfs2_local_alloc_count_bits(alloc); /* hopefully the local alloc has always been recovered before * we load it. */ if (num_used || alloc->id1.bitmap1.i_used || alloc->id1.bitmap1.i_total || la->la_bm_off) mlog(ML_ERROR, "Local alloc hasn't been recovered!\n" "found = %u, set = %u, taken = %u, off = %u\n", num_used, le32_to_cpu(alloc->id1.bitmap1.i_used), le32_to_cpu(alloc->id1.bitmap1.i_total), OCFS2_LOCAL_ALLOC(alloc)->la_bm_off); osb->local_alloc_bh = alloc_bh; osb->local_alloc_state = OCFS2_LA_ENABLED; bail: if (status < 0) if (alloc_bh) brelse(alloc_bh); if (inode) iput(inode); mlog_exit(status); return status; }