errcode_t ocfs2_malloc0(unsigned long size, void *ptr) { errcode_t ret; void **pp = (void **)ptr; ret = ocfs2_malloc(size, ptr); if (ret) return ret; memset(*pp, 0, size); return 0; }
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 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 ocfs2_cache_chain_allocator_blocks(ocfs2_filesys *fs, struct ocfs2_dinode *di) { struct io_vec_unit *ivus = NULL; char *buf = NULL; errcode_t ret = 0; int i, j, count; struct ocfs2_chain_list *cl; struct ocfs2_chain_rec *cr; struct ocfs2_group_desc *gd; io_channel *channel = fs->fs_io; int blocksize = fs->fs_blocksize; int64_t group_size; if (!(di->i_flags & OCFS2_CHAIN_FL)) { ret = OCFS2_ET_INODE_NOT_VALID; goto out; } if (!channel) goto out; if (!di->i_clusters) goto out; group_size = (int64_t)di->i_clusters / di->id2.i_chain.cl_cpg; group_size *= blocksize; if (group_size > io_get_cache_size(channel)) goto out; cl = &(di->id2.i_chain); count = cl->cl_next_free_rec; ret = ocfs2_malloc_blocks(channel, count, &buf); if (ret) goto out; memset(buf, 0, count * blocksize); ret = ocfs2_malloc(sizeof(struct io_vec_unit) * count, &ivus); if (ret) goto out; for (i = 0; i < count; ++i) { cr = &(cl->cl_recs[i]); ivus[i].ivu_blkno = cr->c_blkno; ivus[i].ivu_buf = buf + (i * blocksize); ivus[i].ivu_buflen = blocksize; } while (count) { ret = io_vec_read_blocks(channel, ivus, count); if (ret) goto out; for (i = 0, j = 0; i < count; ++i) { gd = (struct ocfs2_group_desc *)ivus[i].ivu_buf; ret = ocfs2_validate_meta_ecc(fs, ivus[i].ivu_buf, &gd->bg_check); if (ret) goto out; if (memcmp(gd->bg_signature, OCFS2_GROUP_DESC_SIGNATURE, strlen(OCFS2_GROUP_DESC_SIGNATURE))) { ret = OCFS2_ET_BAD_GROUP_DESC_MAGIC; goto out; } ocfs2_swap_group_desc_to_cpu(fs, gd); if ((gd->bg_next_group > OCFS2_SUPER_BLOCK_BLKNO) && (gd->bg_next_group < fs->fs_blocks)) { ivus[j].ivu_blkno = gd->bg_next_group; memset(ivus[j].ivu_buf, 0, blocksize); ivus[j].ivu_buflen = blocksize; j++; } } count = j; } out: ocfs2_free(&ivus); ocfs2_free(&buf); return ret; }