errcode_t ocfs2_bitmap_alloc_region(ocfs2_bitmap *bitmap, uint64_t start_bit, int bitmap_start, int total_bits, struct ocfs2_bitmap_region **ret_br) { errcode_t ret; struct ocfs2_bitmap_region *br; if (total_bits < 0) return OCFS2_ET_INVALID_BIT; ret = ocfs2_malloc0(sizeof(struct ocfs2_bitmap_region), &br); if (ret) return ret; br->br_start_bit = start_bit; br->br_bitmap_start = bitmap_start; br->br_valid_bits = total_bits; br->br_total_bits = total_bits + bitmap_start; br->br_bytes = ocfs2_align_total(br->br_total_bits); ret = ocfs2_malloc0(br->br_bytes, &br->br_bitmap); if (ret) ocfs2_free(&br); else *ret_br = br; return ret; }
errcode_t io_init_cache(io_channel *channel, size_t nr_blocks) { int i; struct io_cache *ic; char *dbuf; struct io_cache_block *icb_list; errcode_t ret; ret = ocfs2_malloc0(sizeof(struct io_cache), &ic); if (ret) goto out; ic->ic_nr_blocks = nr_blocks; ic->ic_lookup = RB_ROOT; INIT_LIST_HEAD(&ic->ic_lru); ret = ocfs2_malloc_blocks(channel, nr_blocks, &ic->ic_data_buffer); if (ret) goto out; ic->ic_data_buffer_len = (unsigned long)nr_blocks * channel->io_blksize; ret = ocfs2_malloc0(sizeof(struct io_cache_block) * nr_blocks, &ic->ic_metadata_buffer); if (ret) goto out; ic->ic_metadata_buffer_len = (unsigned long)nr_blocks * sizeof(struct io_cache_block); icb_list = ic->ic_metadata_buffer; dbuf = ic->ic_data_buffer; for (i = 0; i < nr_blocks; i++) { icb_list[i].icb_blkno = UINT64_MAX; icb_list[i].icb_buf = dbuf; dbuf += channel->io_blksize; list_add_tail(&icb_list[i].icb_list, &ic->ic_lru); } ic->ic_use_count = 1; channel->io_cache = ic; out: if (ret) io_free_cache(ic); return ret; }
errcode_t ocfs2_chain_iterate(ocfs2_filesys *fs, uint64_t blkno, int (*func)(ocfs2_filesys *fs, uint64_t gd_blkno, int chain_num, void *priv_data), void *priv_data) { int iret = 0; char *buf; struct ocfs2_dinode *inode; errcode_t ret; struct chain_context ctxt; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; ret = ocfs2_read_inode(fs, blkno, buf); if (ret) goto out_buf; inode = (struct ocfs2_dinode *)buf; ret = OCFS2_ET_INODE_NOT_VALID; if (!(inode->i_flags & OCFS2_VALID_FL)) goto out_buf; ret = OCFS2_ET_INODE_CANNOT_BE_ITERATED; if (!(inode->i_flags & OCFS2_CHAIN_FL)) goto out_buf; ret = ocfs2_malloc0(fs->fs_blocksize, &ctxt.gd_buf); if (ret) goto out_gd_buf; ctxt.fs = fs; ctxt.func = func; ctxt.priv_data = priv_data; ret = 0; iret |= chain_iterate_cl(&inode->id2.i_chain, &ctxt); if (iret & OCFS2_EXTENT_ERROR) ret = ctxt.errcode; if (iret & OCFS2_EXTENT_CHANGED) { /* Do something */ } out_gd_buf: if (ctxt.gd_buf) ocfs2_free(&ctxt.gd_buf); out_buf: ocfs2_free(&buf); return ret; }
/* * This function is private to the library. Bitmap subtypes will * use this to allocate their structure, but their b_ops will * determine how they work. */ errcode_t ocfs2_bitmap_new(ocfs2_filesys *fs, uint64_t total_bits, const char *description, struct ocfs2_bitmap_operations *ops, void *private_data, ocfs2_bitmap **ret_bitmap) { errcode_t ret; ocfs2_bitmap *bitmap; if (!ops->set_bit || !ops->clear_bit || !ops->test_bit) return OCFS2_ET_INVALID_ARGUMENT; ret = ocfs2_malloc0(sizeof(struct _ocfs2_bitmap), &bitmap); if (ret) return ret; bitmap->b_fs = fs; bitmap->b_total_bits = total_bits; bitmap->b_ops = ops; bitmap->b_regions = RB_ROOT; bitmap->b_private = private_data; if (description) { ret = ocfs2_malloc0(sizeof(char) * (strlen(description) + 1), &bitmap->b_description); if (ret) goto out_free; strcpy(bitmap->b_description, description); } *ret_bitmap = bitmap; return 0; out_free: ocfs2_free(&bitmap); return ret; }
static int features_parse_option(struct tunefs_operation *op, char *arg) { int rc = 1; errcode_t err; struct feature_op_state *state = NULL; struct check_supported_context ctxt = { .sc_string = arg, }; if (!arg) { errorf("No features specified\n"); goto out; } err = ocfs2_malloc0(sizeof(struct feature_op_state), &state); if (err) { tcom_err(err, "while processing feature options"); goto out; } state->fo_op = op; err = ocfs2_parse_feature(arg, &state->fo_feature_set, &state->fo_reverse_set); if (err) { tcom_err(err, "while parsing feature options \"%s\"", arg); goto out; } ctxt.sc_state = state; ctxt.sc_action = FEATURE_ENABLE; ocfs2_feature_foreach(&state->fo_feature_set, check_supported_func, &ctxt); if (ctxt.sc_error) goto out; ctxt.sc_action = FEATURE_DISABLE; ocfs2_feature_reverse_foreach(&state->fo_reverse_set, check_supported_func, &ctxt); if (ctxt.sc_error) goto out; rc = 0; out: if (!rc) op->to_private = state; else if (state) ocfs2_free(&state); return rc; }
/* * \a=0x07, \b=0x08, \t=0x09, \n=0x0a, \v=0x0b, \f=0x0c, \r=0x0d */ static char * process_escapes(char *queryfmt) { char *fmt; int i, j; int len; len = strlen(queryfmt); if (ocfs2_malloc0(len + 1, &fmt)) return NULL; for(i = 0, j = 0; i < len; ) { if (queryfmt[i] != '\\') fmt[j++] = queryfmt[i++]; else { switch(queryfmt[i + 1]) { case 'a': fmt[j++] = 0x07; break; case 'b': fmt[j++] = 0x08; break; case 't': fmt[j++] = 0x09; break; case 'n': fmt[j++] = 0x0A; break; case 'v': fmt[j++] = 0x0B; break; case 'f': fmt[j++] = 0x0C; break; case 'r': fmt[j++] = 0x0D; break; default: fmt[j++] = queryfmt[i]; fmt[j++] = queryfmt[i + 1]; break; } i += 2; } } return fmt; }
errcode_t ocfs2_lookup_system_inode(ocfs2_filesys *fs, int type, int slot_num, uint64_t *blkno) { errcode_t ret; char *buf; ret = ocfs2_malloc0(sizeof(char) * (OCFS2_MAX_FILENAME_LEN + 1), &buf); if (ret) return ret; ocfs2_sprintf_system_inode_name(buf, OCFS2_MAX_FILENAME_LEN, type, slot_num); ret = ocfs2_lookup(fs, fs->fs_sysdir_blkno, buf, strlen(buf), NULL, blkno); ocfs2_free(&buf); return ret; }
/* * ocfs2_partition_list() * */ static errcode_t ocfs2_partition_list (struct list_head *dev_list) { errcode_t ret = 0; FILE *proc; char line[256]; char name[256]; char major[256]; char minor[256]; ocfs2_devices *dev; proc = fopen ("/proc/partitions", "r"); if (proc == NULL) { ret = OCFS2_ET_IO; goto bail; } while (fgets (line, sizeof(line), proc) != NULL) { *major = *minor = *name = '\0'; if (sscanf(line, "%*[ ]%[0-9]%*[ ]%[0-9] %*d %99[^ \t\n]", major, minor, name) != 3) continue; ret = ocfs2_malloc0(sizeof(ocfs2_devices), &dev); if (ret) goto bail; snprintf(dev->dev_name, sizeof(dev->dev_name), "/dev/%s", name); dev->maj_num = strtoul(major, NULL, 0); dev->min_num = strtoul(minor, NULL, 0); list_add_tail(&(dev->list), dev_list); } bail: if (proc) fclose(proc); return ret; }
errcode_t io_open(const char *name, int flags, io_channel **channel) { errcode_t ret; io_channel *chan = NULL; #ifdef __linux__ struct stat stat_buf; struct utsname ut; #endif if (!name || !*name) return OCFS2_ET_BAD_DEVICE_NAME; ret = ocfs2_malloc0(sizeof(struct _io_channel), &chan); if (ret) return ret; ret = ocfs2_malloc(strlen(name)+1, &chan->io_name); if (ret) goto out_chan; strcpy(chan->io_name, name); chan->io_blksize = OCFS2_MIN_BLOCKSIZE; chan->io_flags = (flags & OCFS2_FLAG_RW) ? O_RDWR : O_RDONLY; chan->io_nocache = false; if (!(flags & OCFS2_FLAG_BUFFERED)) chan->io_flags |= O_DIRECT; chan->io_error = 0; chan->io_fd = open64(name, chan->io_flags); if (chan->io_fd < 0) { /* chan will be freed, don't bother with chan->io_error */ if (errno == ENOENT) ret = OCFS2_ET_NAMED_DEVICE_NOT_FOUND; else ret = OCFS2_ET_IO; goto out_name; } if (!(flags & OCFS2_FLAG_BUFFERED)) { ret = io_validate_o_direct(chan); if (ret) goto out_close; /* FIXME: bindraw here */ } /* Workaround from e2fsprogs */ #ifdef __linux__ #undef RLIM_INFINITY #if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4))) #define RLIM_INFINITY ((unsigned long)(~0UL>>1)) #else #define RLIM_INFINITY (~0UL) #endif /* * Work around a bug in 2.4.10-2.4.18 kernels where writes to * block devices are wrongly getting hit by the filesize * limit. This workaround isn't perfect, since it won't work * if glibc wasn't built against 2.2 header files. (Sigh.) * */ if ((flags & OCFS2_FLAG_RW) && (uname(&ut) == 0) && ((ut.release[0] == '2') && (ut.release[1] == '.') && (ut.release[2] == '4') && (ut.release[3] == '.') && (ut.release[4] == '1') && (ut.release[5] >= '0') && (ut.release[5] < '8')) && (fstat(chan->io_fd, &stat_buf) == 0) && (S_ISBLK(stat_buf.st_mode))) { struct rlimit rlim; rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY; setrlimit(RLIMIT_FSIZE, &rlim); getrlimit(RLIMIT_FSIZE, &rlim); if (((unsigned long) rlim.rlim_cur) < ((unsigned long) rlim.rlim_max)) { rlim.rlim_cur = rlim.rlim_max; setrlimit(RLIMIT_FSIZE, &rlim); } } #endif *channel = chan; return 0; out_close: /* Ignore the return, leave the original error */ close(chan->io_fd); out_name: ocfs2_free(&chan->io_name); out_chan: ocfs2_free(&chan); *channel = NULL; return ret; }
errcode_t o2fsck_check_journals(o2fsck_state *ost) { errcode_t ret; int i; ocfs2_filesys *fs = ost->ost_fs; int have_one_good_journal = 0, problem_is_consistent = 1; errcode_t known_problem = 0; struct journal_check_context jc = { .jc_max_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots, }; struct journal_check_info *ji; ret = ocfs2_malloc0(sizeof(struct journal_check_info) * jc.jc_max_slots, &jc.jc_info); if (ret) { com_err(whoami, ret, "while checking journals"); goto out; } ret = check_journal_walk(ost, check_journals_func, &jc); if (ret) { com_err(whoami, ret, "while checking journals"); goto out; } /* * We now know the state of all our journals. If we have at least * one good journal, we have a sane state to fix the others from. * We require all our journals to have identical configuration. * Any inconsistencies (invalid size, bad feature flags) are * probably corruption or a failed tunefs. * * If we don't have a good journal, but all the journals have the * exact same problem, we may be able to handle it as well. We * currently know how to handle these problems: * * JOURNAL_TOO_SMALL * * We simply allocate a default journal size. * * UNSUPP_FEATURE & RO_UNSUPP_FEATURE * * If one journal has an unsupported feature bit set, it's probably * corruption. If all the journals have the exact same feature * bit set, it's certainly a feature we don't understand, and we * want the user to upgrade their fsck. */ for (i = 0; i < jc.jc_max_slots; i++) { ji = &jc.jc_info[i]; if (!ji->i_error) { have_one_good_journal = 1; continue; } if ((ji->i_error != OCFS2_ET_JOURNAL_TOO_SMALL) && (ji->i_error != OCFS2_ET_UNSUPP_FEATURE) && (ji->i_error != OCFS2_ET_RO_UNSUPP_FEATURE)) { problem_is_consistent = 0; continue; } if (known_problem) { if (known_problem != ji->i_error) problem_is_consistent = 0; continue; } known_problem = ji->i_error; } if (!have_one_good_journal) { if (!problem_is_consistent || !known_problem) { ret = jc.jc_info[0].i_error; com_err(whoami, ret, "while checking journals"); goto out; } if ((known_problem == OCFS2_ET_UNSUPP_FEATURE) || (known_problem == OCFS2_ET_RO_UNSUPP_FEATURE)) { com_err(whoami, known_problem, "on all journals. Please upgrade to the " "latest version of fsck.ocfs2"); ret = known_problem; goto out; } if (known_problem != OCFS2_ET_JOURNAL_TOO_SMALL) { ret = known_problem; com_err(whoami, ret, "for all journals"); goto out; } /* Force a valid cluster count for the journals */ jc.jc_max_clusters = ocfs2_clusters_in_bytes(fs, OCFS2_MIN_JOURNAL_SIZE); } ret = check_journal_walk(ost, fix_journals_func, &jc); out: if (jc.jc_info) ocfs2_free(&jc.jc_info); return ret; } static errcode_t ocfs2_clear_journal_flag(ocfs2_filesys *fs, struct ocfs2_dinode *di, int slot) { errcode_t ret = 0; if (!(di->i_flags & OCFS2_VALID_FL) || !(di->i_flags & OCFS2_SYSTEM_FL) || !(di->i_flags & OCFS2_JOURNAL_FL)) return OCFS2_ET_INVALID_ARGUMENT; if (!(di->id1.journal1.ij_flags & OCFS2_JOURNAL_DIRTY_FL)) goto bail; di->id1.journal1.ij_flags &= ~OCFS2_JOURNAL_DIRTY_FL; ret = ocfs2_write_inode(fs, di->i_blkno, (char *)di); if (!ret) printf("Slot %d's journal dirty flag removed\n", slot); bail: return ret; }
errcode_t ocfs2_extent_iterate_inode(ocfs2_filesys *fs, struct ocfs2_dinode *inode, int flags, char *block_buf, int (*func)(ocfs2_filesys *fs, struct ocfs2_extent_rec *rec, int tree_depth, uint32_t ccount, uint64_t ref_blkno, int ref_recno, void *priv_data), void *priv_data) { int i; int iret = 0; struct ocfs2_extent_list *el; errcode_t ret; struct extent_context ctxt; ret = OCFS2_ET_INODE_NOT_VALID; if (!(inode->i_flags & OCFS2_VALID_FL)) goto out; ret = OCFS2_ET_INODE_CANNOT_BE_ITERATED; if (inode->i_flags & (OCFS2_SUPER_BLOCK_FL | OCFS2_LOCAL_ALLOC_FL | OCFS2_CHAIN_FL)) goto out; el = &inode->id2.i_list; if (el->l_tree_depth) { ret = ocfs2_malloc0(sizeof(char *) * el->l_tree_depth, &ctxt.eb_bufs); if (ret) goto out; if (block_buf) { ctxt.eb_bufs[0] = block_buf; } else { ret = ocfs2_malloc0(fs->fs_blocksize * el->l_tree_depth, &ctxt.eb_bufs[0]); if (ret) goto out_eb_bufs; } for (i = 1; i < el->l_tree_depth; i++) { ctxt.eb_bufs[i] = ctxt.eb_bufs[0] + i * fs->fs_blocksize; } } else ctxt.eb_bufs = NULL; ctxt.fs = fs; ctxt.func = func; ctxt.priv_data = priv_data; ctxt.flags = flags; ctxt.ccount = 0; ctxt.last_eb_blkno = 0; ctxt.last_eb_cpos = 0; ret = 0; iret |= extent_iterate_el(el, 0, &ctxt); if (iret & OCFS2_EXTENT_ERROR) ret = ctxt.errcode; if (iret & OCFS2_EXTENT_ABORT) goto out_abort; /* we can only trust ctxt.last_eb_blkno if we walked the whole tree */ if (inode->i_last_eb_blk != ctxt.last_eb_blkno) { inode->i_last_eb_blk = ctxt.last_eb_blkno; iret |= OCFS2_EXTENT_CHANGED; } out_abort: if (!ret && (iret & OCFS2_EXTENT_CHANGED)) ret = ocfs2_write_inode(fs, inode->i_blkno, (char *)inode); out_eb_bufs: if (ctxt.eb_bufs) { if (!block_buf && ctxt.eb_bufs[0]) ocfs2_free(&ctxt.eb_bufs[0]); ocfs2_free(&ctxt.eb_bufs); } out: return ret; }
/* * This function will iterate the chain_rec and do the following modifications: * 1. record all the groups in the chains. * 2. for every group, do: * 1) modify Sub Alloc Slot in extent block/inodes accordingly. * 2) change the GROUP_PARENT according to its future owner. * 3) link the group to the new slot files. */ static errcode_t move_chain_rec(ocfs2_filesys *fs, struct relink_ctxt *ctxt) { errcode_t ret = 0; int i, start, end = 1; uint64_t blkno, gd_blkno = ctxt->cr->c_blkno; struct ocfs2_group_desc *gd = NULL; struct moved_group *group = NULL, *group_head = NULL; if (gd_blkno == 0) goto bail; /* Record the group in the relink_ctxt. * * We record the group in a reverse order, so the first group * will be at the end of the group list. This is useful for * fsck.ocfs2 when any error happens during the move of groups * and we can safely move the group also. */ while (gd_blkno) { ret = ocfs2_malloc0(sizeof(struct moved_group), &group); if (ret) goto bail; memset(group, 0, sizeof(struct moved_group)); /* We insert the group first in case of any further error * will not cause memory leak. */ group->next = group_head; group_head = group; ret = ocfs2_malloc_block(fs->fs_io, &group->gd_buf); if (ret) goto bail; ret = ocfs2_read_group_desc(fs, gd_blkno, group->gd_buf); if (ret) goto bail; group->blkno = gd_blkno; gd = (struct ocfs2_group_desc *)group->gd_buf; gd_blkno = gd->bg_next_group; } group = group_head; while (group) { gd = (struct ocfs2_group_desc *)group->gd_buf; end = 1; /* Modify the "Sub Alloc Slot" in the extent block/inodes. */ while (end < gd->bg_bits) { start = ocfs2_find_next_bit_set(gd->bg_bitmap, gd->bg_bits, end); if (start >= gd->bg_bits) break; end = ocfs2_find_next_bit_clear(gd->bg_bitmap, gd->bg_bits, start); for (i = start; i < end; i++) { blkno = group->blkno + i; ret = change_sub_alloc_slot(fs, blkno, ctxt); if (ret) goto bail; } } /* move the group to the new slots. */ ret = move_group(fs, ctxt, group); if (ret) goto bail; group = group->next; } bail: group = group_head; while (group) { group_head = group->next; if (group->gd_buf) ocfs2_free(&group->gd_buf); ocfs2_free(&group); group = group_head; } return ret; }
/* * allocate ocfs2_image_bitmap_arr and ocfs2 image bitmap blocks. o2image bitmap * block is of size OCFS2_IMAGE_BITMAP_BLOCKSIZE and ocfs2_image_bitmap_arr * tracks the bitmap blocks */ errcode_t ocfs2_image_alloc_bitmap(ocfs2_filesys *ofs) { uint64_t blks, allocsize, leftsize; struct ocfs2_image_state *ost = ofs->ost; int indx, i, n; errcode_t ret; char *buf; ost->ost_bmpblks = ((ost->ost_fsblkcnt - 1) / (OCFS2_IMAGE_BITS_IN_BLOCK)) + 1; ost->ost_bmpblksz = OCFS2_IMAGE_BITMAP_BLOCKSIZE; blks = ost->ost_bmpblks; /* allocate memory for an array to track bitmap blocks */ ret = ocfs2_malloc0((blks * sizeof(ocfs2_image_bitmap_arr)), &ost->ost_bmparr); if (ret) return ret; allocsize = blks * OCFS2_IMAGE_BITMAP_BLOCKSIZE; leftsize = allocsize; indx = 0; /* allocate bitmap blocks and assign blocks to above array */ while (leftsize) { ret = ocfs2_malloc_blocks(ofs->fs_io, allocsize/io_get_blksize(ofs->fs_io), &buf); if (ret && (ret != -ENOMEM)) goto out; if (ret == -ENOMEM) { if (allocsize == OCFS2_IMAGE_BITMAP_BLOCKSIZE) goto out; allocsize >>= 1; if (allocsize % OCFS2_IMAGE_BITMAP_BLOCKSIZE) { allocsize /= OCFS2_IMAGE_BITMAP_BLOCKSIZE; allocsize *= OCFS2_IMAGE_BITMAP_BLOCKSIZE; } continue; } n = allocsize / OCFS2_IMAGE_BITMAP_BLOCKSIZE; for (i = 0; i < n; i++) { ost->ost_bmparr[indx].arr_set_bit_cnt = 0; ost->ost_bmparr[indx].arr_map = ((char *)buf + (i * OCFS2_IMAGE_BITMAP_BLOCKSIZE)); /* remember buf address to free it later */ if (!i) ost->ost_bmparr[indx].arr_self = buf; indx++; } leftsize -= allocsize; if (leftsize <= allocsize) allocsize = leftsize; } out: /* If allocation failed free and return error */ if (leftsize) { for (i = 0; i < indx; i++) if (ost->ost_bmparr[i].arr_self) ocfs2_free(&ost->ost_bmparr[i].arr_self); ocfs2_free(&ost->ost_bmparr); } return ret; }
/* * This routine loads bitmap blocks from an o2image image file into memory. * This process happens during file open. bitmap blocks reside towards * the end of the imagefile. */ errcode_t ocfs2_image_load_bitmap(ocfs2_filesys *ofs) { struct ocfs2_image_state *ost; struct ocfs2_image_hdr *hdr; uint64_t blk_off, bits_set; int i, j, fd; ssize_t count; errcode_t ret; char *blk; ret = ocfs2_malloc0(sizeof(struct ocfs2_image_state), &ofs->ost); if (ret) return ret; ost = ofs->ost; ret = ocfs2_malloc_block(ofs->fs_io, &blk); if (ret) return ret; /* read ocfs2 image header */ ret = io_read_block(ofs->fs_io, 0, 1, blk); if (ret) goto out; hdr = (struct ocfs2_image_hdr *)blk; ocfs2_image_swap_header(hdr); ret = OCFS2_ET_BAD_MAGIC; if (hdr->hdr_magic != OCFS2_IMAGE_MAGIC) goto out; if (memcmp(hdr->hdr_magic_desc, OCFS2_IMAGE_DESC, sizeof(OCFS2_IMAGE_DESC))) goto out; ret = OCFS2_ET_OCFS_REV; if (hdr->hdr_version > OCFS2_IMAGE_VERSION) goto out; ost->ost_fsblkcnt = hdr->hdr_fsblkcnt; ost->ost_fsblksz = hdr->hdr_fsblksz; ost->ost_imgblkcnt = hdr->hdr_imgblkcnt; ost->ost_bmpblksz = hdr->hdr_bmpblksz; ret = ocfs2_image_alloc_bitmap(ofs); if (ret) return ret; /* load bitmap blocks ocfs2 image state */ bits_set = 0; fd = io_get_fd(ofs->fs_io); blk_off = (ost->ost_imgblkcnt + 1) * ost->ost_fsblksz; for (i = 0; i < ost->ost_bmpblks; i++) { ost->ost_bmparr[i].arr_set_bit_cnt = bits_set; /* * we don't use io_read_block as ocfs2 image bitmap block size * could be different from filesystem block size */ count = pread64(fd, ost->ost_bmparr[i].arr_map, ost->ost_bmpblksz, blk_off); if (count < 0) { ret = OCFS2_ET_IO; goto out; } /* add bits set in this bitmap */ for (j = 0; j < (ost->ost_bmpblksz * 8); j++) if (ocfs2_test_bit(j, ost->ost_bmparr[i].arr_map)) bits_set++; blk_off += ost->ost_bmpblksz; } out: if (blk) ocfs2_free(&blk); return ret; }
static int walk_tree_func(struct ocfs2_dir_entry *dentry, int offset, int blocksize, char *buf, void *priv_data) { errcode_t ret; int len, oldval; int reti = 0; char *old_path, *path; struct walk_path *wp = priv_data; if (!strncmp(dentry->name, ".", dentry->name_len) || !strncmp(dentry->name, "..", dentry->name_len)) return 0; len = strlen(wp->path); if (len + dentry->name_len > 4095) { fprintf(stderr, "name is too long in %s\n", wp->path); return OCFS2_DIRENT_ABORT; } ret = ocfs2_malloc0(4096, &path); if (ret) { com_err(wp->argv0, ret, "while allocating path memory in %s\n", wp->path); return OCFS2_DIRENT_ABORT; } memcpy(path, wp->path, len); memcpy(path + len, dentry->name, dentry->name_len); if (dentry->file_type == OCFS2_FT_DIR) path[len + dentry->name_len] = '/'; if (wp->check_dups) { ret = ocfs2_bitmap_test(wp->dup_map, dentry->inode, &oldval); if (oldval) { fprintf(stdout, "Dup! %20"PRIu64" %s\n", (uint64_t)dentry->inode, path); } goto out; } oldval = 0; ret = ocfs2_bitmap_set(wp->inode_map, dentry->inode, &oldval); if (ret) { com_err(wp->argv0, ret, "while setting bitmap bit %"PRIu64"\n", (uint64_t)dentry->inode); reti = OCFS2_DIRENT_ABORT; goto out; } if (oldval) { wp->has_dups = 1; ret = ocfs2_bitmap_set(wp->dup_map, dentry->inode, NULL); if (ret) { com_err(wp->argv0, ret, "while setting dup bit %"PRIu64"\n", (uint64_t)dentry->inode); reti = OCFS2_DIRENT_ABORT; goto out; } } if (!wp->quiet) fprintf(stdout, "%20"PRIu64" %s\n", (uint64_t)dentry->inode, path); if (dentry->file_type == OCFS2_FT_DIR) { old_path = wp->path; wp->path = path; ret = ocfs2_dir_iterate(wp->fs, dentry->inode, 0, NULL, walk_tree_func, wp); if (ret) { com_err(wp->argv0, ret, "while walking %s", wp->path); reti = OCFS2_DIRENT_ABORT; } wp->path = old_path; } out: ocfs2_free(&path); return reti; }
/* Try and replay the slots journals if they're dirty. This only returns * a non-zero error if the caller should not continue. */ errcode_t o2fsck_replay_journals(ocfs2_filesys *fs, int *replayed) { errcode_t err = 0, ret = 0; struct journal_info *jis = NULL, *ji; journal_superblock_t *jsb; char *buf = NULL; int journal_trouble = 0; uint16_t i, max_slots; ocfs2_bitmap *used_blocks = NULL; max_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots; ret = ocfs2_block_bitmap_new(fs, "journal blocks", &used_blocks); if (ret) { com_err(whoami, ret, "while allocating journal block bitmap"); goto out; } ret = ocfs2_malloc_blocks(fs->fs_io, 1, &buf); if (ret) { com_err(whoami, ret, "while allocating room to read journal " "blocks"); goto out; } ret = ocfs2_malloc0(sizeof(struct journal_info) * max_slots, &jis); if (ret) { com_err(whoami, ret, "while allocating an array of block " "numbers for journal replay"); goto out; } printf("Checking each slot's journal.\n"); for (i = 0, ji = jis; i < max_slots; i++, ji++) { ji->ji_used_blocks = used_blocks; ji->ji_revoke = RB_ROOT; ji->ji_slot = i; /* sets ji->ji_replay */ err = prep_journal_info(fs, i, ji); if (err) { printf("Slot %d seems to have a corrupt journal.\n", i); journal_trouble = 1; continue; } if (!ji->ji_replay) { verbosef("slot %d is clean\n", i); continue; } err = walk_journal(fs, i, ji, buf, 0); if (err) { printf("Slot %d's journal can not be replayed.\n", i); journal_trouble = 1; } } for (i = 0, ji = jis; i < max_slots; i++, ji++) { if (!ji->ji_replay) continue; printf("Replaying slot %d's journal.\n", i); err = walk_journal(fs, i, ji, buf, 1); if (err) { journal_trouble = 1; continue; } jsb = ji->ji_jsb; /* reset the journal */ jsb->s_start = 0; if (ji->ji_set_final_seq) jsb->s_sequence = ji->ji_final_seq + 1; /* we don't write back a clean 'mounted' bit here. That would * have to also include having recovered the orphan dir. we * updated s_start, though, so we won't replay the journal * again. */ err = ocfs2_write_journal_superblock(fs, ji->ji_jsb_block, (char *)ji->ji_jsb); if (err) { com_err(whoami, err, "while writing slot %d's journal " "super block", i); journal_trouble = 1; } else { printf("Slot %d's journal replayed successfully.\n", i); *replayed = 1; } } /* this is awkward, but we want fsck -n to tell us as much as it * can so we don't want to ask to proceed here. */ if (journal_trouble) printf("*** There were problems replaying journals. Be " "careful in telling fsck to make repairs to this " "filesystem.\n"); ret = 0; out: if (jis) { for (i = 0, ji = jis; i < max_slots; i++, ji++) { if (ji->ji_jsb) ocfs2_free(&ji->ji_jsb); if (ji->ji_cinode) ocfs2_free_cached_inode(fs, ji->ji_cinode); revoke_free_all(&ji->ji_revoke); } ocfs2_free(&jis); } if (buf) ocfs2_free(&buf); if (used_blocks) ocfs2_bitmap_free(used_blocks); return ret; }
errcode_t ocfs2_open(const char *name, int flags, unsigned int superblock, unsigned int block_size, ocfs2_filesys **ret_fs) { ocfs2_filesys *fs; errcode_t ret; int i, len; char *ptr; unsigned char *raw_uuid; ret = ocfs2_malloc0(sizeof(ocfs2_filesys), &fs); if (ret) return ret; fs->fs_flags = flags; fs->fs_umask = 022; ret = io_open(name, (flags & (OCFS2_FLAG_RO | OCFS2_FLAG_RW | OCFS2_FLAG_BUFFERED)), &fs->fs_io); if (ret) goto out; ret = ocfs2_malloc(strlen(name)+1, &fs->fs_devname); if (ret) goto out; strcpy(fs->fs_devname, name); /* * If OCFS2_FLAG_IMAGE_FILE is specified, it needs to be handled * differently */ if (flags & OCFS2_FLAG_IMAGE_FILE) { ret = ocfs2_image_load_bitmap(fs); if (ret) goto out; if (!superblock) superblock = fs->ost->ost_superblocks[0]; if (!block_size) block_size = fs->ost->ost_fsblksz; } /* image file is not a device */ if (!(flags & OCFS2_FLAG_IMAGE_FILE)) { if (io_is_device_readonly(fs->fs_io)) fs->fs_flags |= OCFS2_FLAG_HARD_RO; } /* * If OCFS2_FLAG_NO_REV_CHECK is specified, fsck (or someone * like it) is asking to ignore the OCFS vol_header at * block 0. */ if (!(flags & OCFS2_FLAG_NO_REV_CHECK)) { ret = ocfs2_validate_ocfs1_header(fs); if (ret) goto out; } if (superblock) { ret = OCFS2_ET_INVALID_ARGUMENT; if (!block_size) goto out; io_set_blksize(fs->fs_io, block_size); ret = ocfs2_read_super(fs, (uint64_t)superblock, NULL); } else { superblock = OCFS2_SUPER_BLOCK_BLKNO; if (block_size) { io_set_blksize(fs->fs_io, block_size); ret = ocfs2_read_super(fs, (uint64_t)superblock, NULL); } else { for (block_size = io_get_blksize(fs->fs_io); block_size <= OCFS2_MAX_BLOCKSIZE; block_size <<= 1) { io_set_blksize(fs->fs_io, block_size); ret = ocfs2_read_super(fs, (uint64_t)superblock, NULL); if ((ret == OCFS2_ET_BAD_MAGIC) || (ret == OCFS2_ET_IO)) continue; break; } } } if (ret) goto out; fs->fs_blocksize = block_size; if (superblock == OCFS2_SUPER_BLOCK_BLKNO) { ret = ocfs2_malloc_block(fs->fs_io, &fs->fs_orig_super); if (ret) goto out; memcpy((char *)fs->fs_orig_super, (char *)fs->fs_super, fs->fs_blocksize); } #if 0 ret = OCFS2_ET_REV_TOO_HIGH; if (fs->fs_super->id2.i_super.s_major_rev_level > OCFS2_LIB_CURRENT_REV) goto out; #endif if (flags & OCFS2_FLAG_STRICT_COMPAT_CHECK) { ret = OCFS2_ET_UNSUPP_FEATURE; if (OCFS2_RAW_SB(fs->fs_super)->s_feature_compat & ~OCFS2_LIB_FEATURE_COMPAT_SUPP) goto out; /* We need to check s_tunefs_flag also to make sure * fsck.ocfs2 won't try to clean up an aborted tunefs * that it doesn't know. */ if (OCFS2_HAS_INCOMPAT_FEATURE(OCFS2_RAW_SB(fs->fs_super), OCFS2_FEATURE_INCOMPAT_TUNEFS_INPROG) && (OCFS2_RAW_SB(fs->fs_super)->s_tunefs_flag & ~OCFS2_LIB_ABORTED_TUNEFS_SUPP)) goto out; } ret = OCFS2_ET_UNSUPP_FEATURE; if (OCFS2_RAW_SB(fs->fs_super)->s_feature_incompat & ~OCFS2_LIB_FEATURE_INCOMPAT_SUPP) goto out; ret = OCFS2_ET_RO_UNSUPP_FEATURE; if ((flags & OCFS2_FLAG_RW) && (OCFS2_RAW_SB(fs->fs_super)->s_feature_ro_compat & ~OCFS2_LIB_FEATURE_RO_COMPAT_SUPP)) goto out; ret = OCFS2_ET_UNSUPP_FEATURE; if (!(flags & OCFS2_FLAG_HEARTBEAT_DEV_OK) && (OCFS2_RAW_SB(fs->fs_super)->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_HEARTBEAT_DEV)) goto out; ret = OCFS2_ET_CORRUPT_SUPERBLOCK; if (!OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits) goto out; if (fs->fs_super->i_blkno != superblock) goto out; if ((OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits < 12) || (OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits > 20)) goto out; if (!OCFS2_RAW_SB(fs->fs_super)->s_root_blkno || !OCFS2_RAW_SB(fs->fs_super)->s_system_dir_blkno) goto out; if (OCFS2_RAW_SB(fs->fs_super)->s_max_slots > OCFS2_MAX_SLOTS) goto out; ret = ocfs2_malloc0(OCFS2_RAW_SB(fs->fs_super)->s_max_slots * sizeof(ocfs2_cached_inode *), &fs->fs_inode_allocs); if (ret) goto out; ret = ocfs2_malloc0(OCFS2_RAW_SB(fs->fs_super)->s_max_slots * sizeof(ocfs2_cached_inode *), &fs->fs_eb_allocs); if (ret) goto out; ret = OCFS2_ET_UNEXPECTED_BLOCK_SIZE; if (block_size != (1U << OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits)) goto out; fs->fs_clustersize = 1 << OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits; /* FIXME: Read the system dir */ fs->fs_root_blkno = OCFS2_RAW_SB(fs->fs_super)->s_root_blkno; fs->fs_sysdir_blkno = OCFS2_RAW_SB(fs->fs_super)->s_system_dir_blkno; fs->fs_clusters = fs->fs_super->i_clusters; fs->fs_blocks = ocfs2_clusters_to_blocks(fs, fs->fs_clusters); fs->fs_first_cg_blkno = OCFS2_RAW_SB(fs->fs_super)->s_first_cluster_group; raw_uuid = OCFS2_RAW_SB(fs->fs_super)->s_uuid; for (i = 0, ptr = fs->uuid_str; i < OCFS2_VOL_UUID_LEN; i++) { /* print with null */ len = snprintf(ptr, 3, "%02X", raw_uuid[i]); if (len != 2) { ret = OCFS2_ET_INTERNAL_FAILURE; goto out; } /* then only advace past the last char */ ptr += 2; } *ret_fs = fs; return 0; out: if (fs->fs_inode_allocs) ocfs2_free(&fs->fs_inode_allocs); ocfs2_freefs(fs); return ret; }
errcode_t ocfs2_extent_iterate_xattr(ocfs2_filesys *fs, struct ocfs2_extent_list *el, uint64_t last_eb_blk, int flags, int (*func)(ocfs2_filesys *fs, struct ocfs2_extent_rec *rec, int tree_depth, uint32_t ccount, uint64_t ref_blkno, int ref_recno, void *priv_data), void *priv_data, int *changed) { int i; int iret = 0; errcode_t ret; struct extent_context ctxt; if (el->l_tree_depth) { ret = ocfs2_malloc0(sizeof(char *) * el->l_tree_depth, &ctxt.eb_bufs); if (ret) goto out; ret = ocfs2_malloc0(fs->fs_blocksize * el->l_tree_depth, &ctxt.eb_bufs[0]); if (ret) goto out_eb_bufs; for (i = 1; i < el->l_tree_depth; i++) { ctxt.eb_bufs[i] = ctxt.eb_bufs[0] + i * fs->fs_blocksize; } } else ctxt.eb_bufs = NULL; ctxt.fs = fs; ctxt.func = func; ctxt.priv_data = priv_data; ctxt.flags = flags; ctxt.ccount = 0; ctxt.last_eb_blkno = 0; ctxt.last_eb_cpos = 0; ret = 0; iret |= extent_iterate_el(el, 0, &ctxt); if (iret & OCFS2_EXTENT_ERROR) ret = ctxt.errcode; if (iret & OCFS2_EXTENT_ABORT) goto out_abort; if (last_eb_blk != ctxt.last_eb_blkno) { last_eb_blk = ctxt.last_eb_blkno; iret |= OCFS2_EXTENT_CHANGED; } out_abort: if (!ret && (iret & OCFS2_EXTENT_CHANGED)) *changed = 1; out_eb_bufs: if (ctxt.eb_bufs) { if (ctxt.eb_bufs[0]) ocfs2_free(&ctxt.eb_bufs[0]); ocfs2_free(&ctxt.eb_bufs); } out: return ret; }