/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * alloc.c * * Allocate inodes, extent_blocks, and actual data space. Part of the * OCFS2 userspace library. * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License, version 2, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #define _XOPEN_SOURCE 600 /* Triggers magic in features.h */ #define _LARGEFILE64_SOURCE #include #include #include "ocfs2/ocfs2.h" static errcode_t ocfs2_chain_alloc_with_io(ocfs2_filesys *fs, ocfs2_cached_inode *cinode, uint64_t *gd_blkno, uint16_t *suballoc_bit, uint64_t *bitno) { errcode_t ret; if (!cinode->ci_chains) { ret = ocfs2_load_chain_allocator(fs, cinode); if (ret) return ret; } ret = ocfs2_chain_alloc(fs, cinode, gd_blkno, suballoc_bit, bitno); if (ret) return ret; return ocfs2_write_chain_allocator(fs, cinode); } static errcode_t ocfs2_chain_free_with_io(ocfs2_filesys *fs, ocfs2_cached_inode *cinode, uint64_t bitno) { errcode_t ret; if (!cinode->ci_chains) { ret = ocfs2_load_chain_allocator(fs, cinode); if (ret) return ret; } ret = ocfs2_chain_free(fs, cinode, bitno); if (ret) return ret; return ocfs2_write_chain_allocator(fs, cinode); } static errcode_t ocfs2_load_allocator(ocfs2_filesys *fs, int type, int slot_num, ocfs2_cached_inode **alloc_cinode) { errcode_t ret; uint64_t blkno; if (!*alloc_cinode) { ret = ocfs2_lookup_system_inode(fs, type, slot_num, &blkno); if (ret) return ret; ret = ocfs2_read_cached_inode(fs, blkno, alloc_cinode); if (ret) return ret; } if (!(*alloc_cinode)->ci_chains) { ret = ocfs2_load_chain_allocator(fs, *alloc_cinode); if (ret) return ret; } return 0; } /* * This function is duplicated in mkfs.ocfs2/mkfs.c. * Please keep them in sync. */ static int ocfs2_clusters_per_group(int block_size, int cluster_size_bits) { int megabytes; switch (block_size) { case 4096: case 2048: megabytes = 4; break; case 1024: megabytes = 2; break; case 512: default: megabytes = 1; break; } #define ONE_MB_SHIFT 20 return (megabytes << ONE_MB_SHIFT) >> cluster_size_bits; } static void ocfs2_zero_dinode_id2_with_xattr(int blocksize, struct ocfs2_dinode *di) { unsigned int xattrsize = di->i_xattr_inline_size; if (di->i_dyn_features & OCFS2_INLINE_XATTR_FL) memset(&di->id2, 0, blocksize - offsetof(struct ocfs2_dinode, id2) - xattrsize); else memset(&di->id2, 0, blocksize - offsetof(struct ocfs2_dinode, id2)); } void ocfs2_dinode_new_extent_list(ocfs2_filesys *fs, struct ocfs2_dinode *di) { ocfs2_zero_dinode_id2_with_xattr(fs->fs_blocksize, di); di->id2.i_list.l_tree_depth = 0; di->id2.i_list.l_next_free_rec = 0; di->id2.i_list.l_count = ocfs2_extent_recs_per_inode(fs->fs_blocksize); } void ocfs2_set_inode_data_inline(ocfs2_filesys *fs, struct ocfs2_dinode *di) { struct ocfs2_inline_data *idata = &di->id2.i_data; ocfs2_zero_dinode_id2_with_xattr(fs->fs_blocksize, di); idata->id_count = ocfs2_max_inline_data_with_xattr(fs->fs_blocksize, di); di->i_dyn_features |= OCFS2_INLINE_DATA_FL; } static void ocfs2_init_inode(ocfs2_filesys *fs, struct ocfs2_dinode *di, int16_t slot, uint64_t gd_blkno, uint16_t suballoc_bit, uint64_t blkno, uint16_t mode, uint32_t flags) { int cs_bits = OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits; unsigned int tl_recs; di->i_generation = fs->fs_super->i_generation; di->i_fs_generation = fs->fs_super->i_fs_generation; di->i_blkno = blkno; di->i_suballoc_slot = slot; di->i_suballoc_loc = gd_blkno; di->i_suballoc_bit = suballoc_bit; di->i_uid = di->i_gid = 0; di->i_mode = mode; if (S_ISDIR(di->i_mode)) di->i_links_count = 2; else di->i_links_count = 1; strcpy((char *)di->i_signature, OCFS2_INODE_SIGNATURE); di->i_atime = di->i_ctime = di->i_mtime = time(NULL); di->i_dtime = 0; di->i_flags = flags; if (flags & OCFS2_LOCAL_ALLOC_FL) { di->id2.i_lab.la_size = ocfs2_local_alloc_size(fs->fs_blocksize); return ; } if (flags & OCFS2_CHAIN_FL) { di->id2.i_chain.cl_count = ocfs2_chain_recs_per_inode(fs->fs_blocksize); di->id2.i_chain.cl_cpg = ocfs2_clusters_per_group(fs->fs_blocksize, cs_bits); di->id2.i_chain.cl_bpc = fs->fs_clustersize / fs->fs_blocksize; di->id2.i_chain.cl_next_free_rec = 0; return ; } if (flags & OCFS2_DEALLOC_FL) { tl_recs = ocfs2_truncate_recs_per_inode(fs->fs_blocksize); di->id2.i_dealloc.tl_count = tl_recs; return ; } if (flags & OCFS2_SUPER_BLOCK_FL) return ; if (ocfs2_support_inline_data(OCFS2_RAW_SB(fs->fs_super)) && S_ISDIR(di->i_mode)) ocfs2_set_inode_data_inline(fs, di); else ocfs2_dinode_new_extent_list(fs, di); } static void ocfs2_init_eb(ocfs2_filesys *fs, struct ocfs2_extent_block *eb, uint64_t gd_blkno, uint16_t suballoc_bit, uint64_t blkno) { strcpy((char *)eb->h_signature, OCFS2_EXTENT_BLOCK_SIGNATURE); eb->h_fs_generation = fs->fs_super->i_fs_generation; eb->h_blkno = blkno; eb->h_suballoc_slot = 0; eb->h_suballoc_loc = gd_blkno; eb->h_suballoc_bit = suballoc_bit; eb->h_list.l_count = ocfs2_extent_recs_per_eb(fs->fs_blocksize); } errcode_t ocfs2_new_inode(ocfs2_filesys *fs, uint64_t *ino, int mode) { errcode_t ret; char *buf; uint64_t gd_blkno; uint16_t suballoc_bit; struct ocfs2_dinode *di; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; ret = ocfs2_load_allocator(fs, INODE_ALLOC_SYSTEM_INODE, 0, &fs->fs_inode_allocs[0]); if (ret) goto out; ret = ocfs2_chain_alloc_with_io(fs, fs->fs_inode_allocs[0], &gd_blkno, &suballoc_bit, ino); if (ret == OCFS2_ET_BIT_NOT_FOUND) { ret = ocfs2_chain_add_group(fs, fs->fs_inode_allocs[0]); if (ret) goto out; ret = ocfs2_chain_alloc_with_io(fs, fs->fs_inode_allocs[0], &gd_blkno, &suballoc_bit, ino); if (ret) goto out; } else if (ret) goto out; memset(buf, 0, fs->fs_blocksize); di = (struct ocfs2_dinode *)buf; ocfs2_init_inode(fs, di, 0, gd_blkno, suballoc_bit, *ino, mode, OCFS2_VALID_FL); ret = ocfs2_write_inode(fs, *ino, buf); if (ret) ocfs2_delete_inode(fs, *ino); out: ocfs2_free(&buf); return ret; } errcode_t ocfs2_new_system_inode(ocfs2_filesys *fs, uint64_t *ino, int mode, int flags) { errcode_t ret; char *buf; uint64_t gd_blkno; uint16_t suballoc_bit; struct ocfs2_dinode *di; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; ret = ocfs2_load_allocator(fs, GLOBAL_INODE_ALLOC_SYSTEM_INODE, 0, &fs->fs_system_inode_alloc); if (ret) goto out; ret = ocfs2_chain_alloc_with_io(fs, fs->fs_system_inode_alloc, &gd_blkno, &suballoc_bit, ino); if (ret == OCFS2_ET_BIT_NOT_FOUND) { ret = ocfs2_chain_add_group(fs, fs->fs_system_inode_alloc); if (ret) goto out; ret = ocfs2_chain_alloc_with_io(fs, fs->fs_system_inode_alloc, &gd_blkno, &suballoc_bit, ino); if (ret) goto out; } memset(buf, 0, fs->fs_blocksize); di = (struct ocfs2_dinode *)buf; ocfs2_init_inode(fs, di, -1, gd_blkno, suballoc_bit, *ino, mode, (flags | OCFS2_VALID_FL | OCFS2_SYSTEM_FL)); ret = ocfs2_write_inode(fs, *ino, buf); out: ocfs2_free(&buf); return ret; } errcode_t ocfs2_delete_inode(ocfs2_filesys *fs, uint64_t ino) { errcode_t ret; char *buf; struct ocfs2_dinode *di; int16_t slot; ocfs2_cached_inode **inode_alloc; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; ret = ocfs2_read_inode(fs, ino, buf); if (ret) goto out; di = (struct ocfs2_dinode *)buf; slot = di->i_suballoc_slot; if (slot == OCFS2_INVALID_SLOT) { inode_alloc = &fs->fs_system_inode_alloc; ret = ocfs2_load_allocator(fs, GLOBAL_INODE_ALLOC_SYSTEM_INODE, 0, inode_alloc); } else { inode_alloc = &fs->fs_inode_allocs[slot]; ret = ocfs2_load_allocator(fs, INODE_ALLOC_SYSTEM_INODE, slot, inode_alloc); } if (ret) goto out; ret = ocfs2_chain_free_with_io(fs, *inode_alloc, ino); if (ret) goto out; di->i_flags &= ~(OCFS2_VALID_FL | OCFS2_ORPHANED_FL); di->i_dtime = time(NULL); ret = ocfs2_write_inode(fs, di->i_blkno, buf); out: ocfs2_free(&buf); return ret; } errcode_t ocfs2_test_inode_allocated(ocfs2_filesys *fs, uint64_t blkno, int *is_allocated) { int16_t slot; uint16_t max_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots; ocfs2_cached_inode **ci; int type; errcode_t ret = OCFS2_ET_INTERNAL_FAILURE; for (slot = OCFS2_INVALID_SLOT; slot != max_slots; slot++) { if (slot == OCFS2_INVALID_SLOT) { type = GLOBAL_INODE_ALLOC_SYSTEM_INODE; ci = &fs->fs_system_inode_alloc; } else { type = INODE_ALLOC_SYSTEM_INODE; ci = &fs->fs_inode_allocs[slot]; } ret = ocfs2_load_allocator(fs, type, slot, ci); if (ret) break; ret = ocfs2_chain_test(fs, *ci, blkno, is_allocated); if (ret != OCFS2_ET_INVALID_BIT) break; } return ret; } errcode_t ocfs2_new_extent_block(ocfs2_filesys *fs, uint64_t *blkno) { errcode_t ret; char *buf; uint64_t gd_blkno; uint16_t suballoc_bit; struct ocfs2_extent_block *eb; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; ret = ocfs2_load_allocator(fs, EXTENT_ALLOC_SYSTEM_INODE, 0, &fs->fs_eb_allocs[0]); if (ret) goto out; ret = ocfs2_chain_alloc_with_io(fs, fs->fs_eb_allocs[0], &gd_blkno, &suballoc_bit, blkno); if (ret == OCFS2_ET_BIT_NOT_FOUND) { ret = ocfs2_chain_add_group(fs, fs->fs_eb_allocs[0]); if (ret) goto out; ret = ocfs2_chain_alloc_with_io(fs, fs->fs_eb_allocs[0], &gd_blkno, &suballoc_bit, blkno); if (ret) goto out; } else if (ret) goto out; memset(buf, 0, fs->fs_blocksize); eb = (struct ocfs2_extent_block *)buf; ocfs2_init_eb(fs, eb, gd_blkno, suballoc_bit, *blkno); ret = ocfs2_write_extent_block(fs, *blkno, buf); out: ocfs2_free(&buf); return ret; } errcode_t ocfs2_delete_xattr_block(ocfs2_filesys *fs, uint64_t blkno) { errcode_t ret; char *buf; int slot; struct ocfs2_xattr_block *xb = NULL; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; ret = ocfs2_read_xattr_block(fs, blkno, buf); if (ret) goto out; xb = (struct ocfs2_xattr_block *)buf; slot = xb->xb_suballoc_slot; ret = ocfs2_load_allocator(fs, EXTENT_ALLOC_SYSTEM_INODE, slot, &fs->fs_eb_allocs[slot]); if (ret) goto out; ret = ocfs2_chain_free_with_io(fs, fs->fs_eb_allocs[slot], blkno); if (ret) goto out; out: ocfs2_free(&buf); return ret; } errcode_t ocfs2_delete_extent_block(ocfs2_filesys *fs, uint64_t blkno) { errcode_t ret; char *buf; struct ocfs2_extent_block *eb; int slot; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; ret = ocfs2_read_extent_block(fs, blkno, buf); if (ret) goto out; eb = (struct ocfs2_extent_block *)buf; slot = eb->h_suballoc_slot; ret = ocfs2_load_allocator(fs, EXTENT_ALLOC_SYSTEM_INODE, slot, &fs->fs_eb_allocs[slot]); if (ret) goto out; ret = ocfs2_chain_free_with_io(fs, fs->fs_eb_allocs[slot], blkno); if (ret) goto out; ret = ocfs2_write_extent_block(fs, eb->h_blkno, buf); out: ocfs2_free(&buf); return ret; } errcode_t ocfs2_delete_refcount_block(ocfs2_filesys *fs, uint64_t blkno) { errcode_t ret; char *buf; struct ocfs2_refcount_block *rb; int slot; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; ret = ocfs2_read_refcount_block(fs, blkno, buf); if (ret) goto out; rb = (struct ocfs2_refcount_block *)buf; slot = rb->rf_suballoc_slot; ret = ocfs2_load_allocator(fs, EXTENT_ALLOC_SYSTEM_INODE, slot, &fs->fs_eb_allocs[slot]); if (ret) goto out; ret = ocfs2_chain_free_with_io(fs, fs->fs_eb_allocs[slot], blkno); out: ocfs2_free(&buf); return ret; } static void ocfs2_init_rb(ocfs2_filesys *fs, struct ocfs2_refcount_block *rb, uint64_t gd_blkno, uint16_t suballoc_bit, uint64_t blkno, uint64_t root_blkno, uint32_t rf_generation) { strcpy((void *)rb, OCFS2_REFCOUNT_BLOCK_SIGNATURE); rb->rf_fs_generation = fs->fs_super->i_fs_generation; rb->rf_blkno = blkno; rb->rf_suballoc_slot = 0; rb->rf_suballoc_loc = gd_blkno; rb->rf_suballoc_bit = suballoc_bit; rb->rf_parent = root_blkno; if (root_blkno) rb->rf_flags = OCFS2_REFCOUNT_LEAF_FL; rb->rf_records.rl_count = ocfs2_refcount_recs_per_rb(fs->fs_blocksize); rb->rf_generation = rf_generation; } errcode_t ocfs2_new_refcount_block(ocfs2_filesys *fs, uint64_t *blkno, uint64_t root_blkno, uint32_t rf_generation) { errcode_t ret; char *buf; uint64_t gd_blkno; uint16_t suballoc_bit; struct ocfs2_refcount_block *rb; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) return ret; ret = ocfs2_load_allocator(fs, EXTENT_ALLOC_SYSTEM_INODE, 0, &fs->fs_eb_allocs[0]); if (ret) goto out; ret = ocfs2_chain_alloc_with_io(fs, fs->fs_eb_allocs[0], &gd_blkno, &suballoc_bit, blkno); if (ret == OCFS2_ET_BIT_NOT_FOUND) { ret = ocfs2_chain_add_group(fs, fs->fs_eb_allocs[0]); if (ret) goto out; ret = ocfs2_chain_alloc_with_io(fs, fs->fs_eb_allocs[0], &gd_blkno, &suballoc_bit, blkno); if (ret) goto out; } else if (ret) goto out; memset(buf, 0, fs->fs_blocksize); rb = (struct ocfs2_refcount_block *)buf; ocfs2_init_rb(fs, rb, gd_blkno, suballoc_bit, *blkno, root_blkno, rf_generation); ret = ocfs2_write_refcount_block(fs, *blkno, buf); out: ocfs2_free(&buf); return ret; } errcode_t ocfs2_grow_chain_allocator(ocfs2_filesys *fs, int type, int slot_num, uint32_t num_clusters) { errcode_t ret = OCFS2_ET_INVALID_ARGUMENT; ocfs2_cached_inode *ci; int i, num_groups, cpg; switch (type) { case EXTENT_ALLOC_SYSTEM_INODE: ci = fs->fs_eb_allocs[slot_num]; break; case INODE_ALLOC_SYSTEM_INODE: ci = fs->fs_inode_allocs[slot_num]; break; case GLOBAL_INODE_ALLOC_SYSTEM_INODE: ci = fs->fs_system_inode_alloc; break; default: goto out; } ret = ocfs2_load_allocator(fs, type, slot_num, &ci); if (ret) goto out; cpg = ci->ci_inode->id2.i_chain.cl_cpg; num_groups = (num_clusters + cpg - 1) / cpg; for (i = 0; i < num_groups; ++i) { ret = ocfs2_chain_add_group(fs, ci); if (ret) goto out; } out: return ret; } /* only initiate part of dx_root: * dr_subllaoc_slot * dr_sbualloc_bit * dr_fs_generation * dr_blkno * dr_flags */ static void init_dx_root(ocfs2_filesys *fs, struct ocfs2_dx_root_block *dx_root, int slot, uint64_t gd_blkno, uint16_t suballoc_bit, uint64_t dr_blkno) { memset(dx_root, 0, fs->fs_blocksize); strcpy((char *)dx_root->dr_signature, OCFS2_DX_ROOT_SIGNATURE); dx_root->dr_suballoc_slot = slot; dx_root->dr_suballoc_loc = gd_blkno; dx_root->dr_suballoc_bit = suballoc_bit; dx_root->dr_fs_generation = fs->fs_super->i_fs_generation; dx_root->dr_blkno = dr_blkno; dx_root->dr_flags |= OCFS2_DX_FLAG_INLINE; } errcode_t ocfs2_new_dx_root(ocfs2_filesys *fs, struct ocfs2_dinode *di, uint64_t *dr_blkno) { errcode_t ret; char *buf = NULL; uint64_t gd_blkno; uint16_t suballoc_bit; struct ocfs2_dx_root_block *dx_root; int slot; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) goto out; slot = di->i_suballoc_slot; if (slot == (uint16_t)OCFS2_INVALID_SLOT) slot = 0; ret = ocfs2_load_allocator(fs, EXTENT_ALLOC_SYSTEM_INODE, slot, &fs->fs_eb_allocs[slot]); if (ret) goto out; ret = ocfs2_chain_alloc_with_io(fs, fs->fs_eb_allocs[slot], &gd_blkno, &suballoc_bit, dr_blkno); if (ret == OCFS2_ET_BIT_NOT_FOUND) { ret = ocfs2_chain_add_group(fs, fs->fs_eb_allocs[slot]); if (ret) goto out; ret = ocfs2_chain_alloc_with_io(fs, fs->fs_eb_allocs[slot], &gd_blkno, &suballoc_bit, dr_blkno); if (ret) goto out; } else if (ret) goto out; dx_root = (struct ocfs2_dx_root_block *)buf; init_dx_root(fs, dx_root, slot, gd_blkno, suballoc_bit, *dr_blkno); ret = ocfs2_write_dx_root(fs, *dr_blkno, (char *)dx_root); out: if (buf) ocfs2_free(&buf); return ret; } errcode_t ocfs2_delete_dx_root(ocfs2_filesys *fs, uint64_t dr_blkno) { errcode_t ret; char *buf = NULL; struct ocfs2_dx_root_block *dx_root; int slot; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) goto out; ret = ocfs2_read_dx_root(fs, dr_blkno, buf); if (ret) goto out; dx_root = (struct ocfs2_dx_root_block *)buf; slot = dx_root->dr_suballoc_slot; ret = ocfs2_load_allocator(fs, EXTENT_ALLOC_SYSTEM_INODE, slot, &fs->fs_eb_allocs[slot]); if (ret) goto out; ret = ocfs2_chain_free_with_io(fs, fs->fs_eb_allocs[slot], dr_blkno); out: if (buf) ocfs2_free(&buf); return ret; } /* XXX what to do about local allocs? * XXX Well, we shouldn't use local allocs to allocate, as we are * userspace and we have the entire bitmap in memory. However, this * doesn't solve the issue of "is space still in dirty local * allocs?" */ errcode_t ocfs2_new_clusters(ocfs2_filesys *fs, uint32_t min, uint32_t requested, uint64_t *start_blkno, uint32_t *clusters_found) { errcode_t ret; uint64_t start_bit; uint64_t found; ret = ocfs2_load_allocator(fs, GLOBAL_BITMAP_SYSTEM_INODE, 0, &fs->fs_cluster_alloc); if (ret) goto out; ret = ocfs2_chain_alloc_range(fs, fs->fs_cluster_alloc, min, requested, &start_bit, &found); if (ret) goto out; *start_blkno = ocfs2_clusters_to_blocks(fs, start_bit); /* We never have enough bits that can be allocated * contiguously to overflow this. The lower level API needs * fixing. */ *clusters_found = (uint32_t) found; ret = ocfs2_write_chain_allocator(fs, fs->fs_cluster_alloc); if (ret) ocfs2_free_clusters(fs, requested, *start_blkno); out: return ret; } errcode_t ocfs2_test_cluster_allocated(ocfs2_filesys *fs, uint32_t cpos, int *is_allocated) { errcode_t ret; ret = ocfs2_load_allocator(fs, GLOBAL_BITMAP_SYSTEM_INODE, 0, &fs->fs_cluster_alloc); if (!ret) { ret = ocfs2_chain_test(fs, fs->fs_cluster_alloc, cpos, is_allocated); } return ret; } errcode_t ocfs2_new_specific_cluster(ocfs2_filesys *fs, uint32_t cpos) { errcode_t ret; int allocatedp = 0; /* Loads the allocator if we need it */ ret = ocfs2_test_cluster_allocated(fs, cpos, &allocatedp); if (ret) goto out; if (allocatedp) { ret = OCFS2_ET_BIT_NOT_FOUND; goto out; } ocfs2_chain_force_val(fs, fs->fs_cluster_alloc, cpos, 1, NULL); ret = ocfs2_write_chain_allocator(fs, fs->fs_cluster_alloc); if (ret) ocfs2_free_clusters(fs, 1, ocfs2_blocks_to_clusters(fs, cpos)); out: return ret; } errcode_t ocfs2_free_clusters(ocfs2_filesys *fs, uint32_t len, uint64_t start_blkno) { errcode_t ret; ret = ocfs2_load_allocator(fs, GLOBAL_BITMAP_SYSTEM_INODE, 0, &fs->fs_cluster_alloc); if (ret) goto out; ret = ocfs2_chain_free_range(fs, fs->fs_cluster_alloc, len, ocfs2_blocks_to_clusters(fs, start_blkno)); if (ret) goto out; /* XXX OK, it's bad if we can't revert this after the io fails */ ret = ocfs2_write_chain_allocator(fs, fs->fs_cluster_alloc); out: return ret; } /* * Test whether clusters have the specified value in the bitmap. * test: expected value * matches: 1 if all bits match test, else 0 */ errcode_t ocfs2_test_clusters(ocfs2_filesys *fs, uint32_t len, uint64_t start_blkno, int test, int *matches) { errcode_t ret; uint32_t start_cluster; int set = 0; *matches = 0; if (!len) return 0; ret = ocfs2_load_allocator(fs, GLOBAL_BITMAP_SYSTEM_INODE, 0, &fs->fs_cluster_alloc); if (ret) goto out; start_cluster = ocfs2_blocks_to_clusters(fs, start_blkno); while (len) { ret = ocfs2_bitmap_test(fs->fs_cluster_alloc->ci_chains, start_cluster, &set); if (ret || set != test) goto out; len--; start_cluster++; } *matches = 1; out: return ret; } #ifdef DEBUG_EXE #include static void print_usage(void) { fprintf(stdout, "debug_alloc \n"); } int main(int argc, char *argv[]) { errcode_t ret; ocfs2_filesys *fs; char *buf; struct ocfs2_dinode *di; uint64_t blkno; if (argc < 3) { print_usage(); return 1; } initialize_ocfs_error_table(); ret = ocfs2_open(argv[2], OCFS2_FLAG_RW, 0, 0, &fs); if (ret) { com_err(argv[0], ret, "while opening \"%s\"", argv[2]); goto out; } ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) { com_err(argv[0], ret, "while allocating buffer"); goto out_close; } di = (struct ocfs2_dinode *)buf; ret = ocfs2_new_inode(fs, &blkno, 0644 | S_IFREG); if (ret) { com_err(argv[0], ret, "while allocating a new inode"); goto out_free; } ret = ocfs2_link(fs, fs->fs_root_blkno, argv[1], blkno, OCFS2_FT_REG_FILE); if (ret) { com_err(argv[0], ret, "while linking inode %"PRIu64, blkno); } out_free: ocfs2_free(&buf); out_close: ret = ocfs2_close(fs); if (ret) { com_err(argv[0], ret, "while closing \"%s\"", argv[2]); } out: return ret; } #endif /* DEBUG_EXE */