static PyObject * fs_read_cached_inode (Filesystem *self, PyObject *args, PyObject *kwargs) { errcode_t ret; unsigned long long blkno; ocfs2_cached_inode *cinode; PyObject *dinode; static char *kwlist[] = { "blkno", NULL }; if (!PyArg_ParseTupleAndKeywords (args, kwargs, "K:read_cached_inode", kwlist, &blkno)) return NULL; CHECK_ERROR (ocfs2_read_cached_inode (self->fs, blkno, &cinode)); dinode = dinode_new (self, cinode->ci_inode); /* XXX: error check */ ocfs2_free_cached_inode (self->fs, cinode); return dinode; }
static errcode_t check_journal_walk(o2fsck_state *ost, errcode_t (*func)(o2fsck_state *ost, ocfs2_cached_inode *ci, struct journal_check_context *jc), struct journal_check_context *jc) { errcode_t ret = 0; uint64_t blkno; ocfs2_filesys *fs = ost->ost_fs; uint16_t i, max_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots; ocfs2_cached_inode *ci = NULL; for (i = 0; i < max_slots; i++) { ret = ocfs2_lookup_system_inode(fs, JOURNAL_SYSTEM_INODE, i, &blkno); if (ret) break; ret = ocfs2_read_cached_inode(fs, blkno, &ci); if (ret) break; jc->jc_this_slot = i; ret = func(ost, ci, jc); if (ret) break; } if (ci) ocfs2_free_cached_inode(fs, ci); return ret; }
static errcode_t check_backup_offsets(ocfs2_filesys *fs) { errcode_t ret; int i, num, val, failed = 0; ocfs2_cached_inode *chain_alloc = NULL; uint64_t blocks[OCFS2_MAX_BACKUP_SUPERBLOCKS]; num = ocfs2_get_backup_super_offsets(fs, blocks, ARRAY_SIZE(blocks)); if (!num) { ret = 1; errorf("Volume on device \"%s\" is too small to contain " "backup superblocks\n", fs->fs_devname); goto bail; } ret = load_global_bitmap(fs, &chain_alloc); if (ret) { tcom_err(ret, "while loading the global bitmap"); goto bail; } for (i = 0; i < num; i++) { ret = ocfs2_bitmap_test(chain_alloc->ci_chains, ocfs2_blocks_to_clusters(fs, blocks[i]), &val); if (ret) { tcom_err(ret, "looking up backup superblock locations " "in the global bitmap"); goto bail; } if (val) { verbosef(VL_APP, "Backup superblock location %d at block " "%"PRIu64" is in use\n", i, blocks[i]); /* in order to verify all the block in the 'blocks', * we don't stop the loop here. */ failed = 1; } } if (failed) { ret = 1; errorf("One or more backup superblock locations are " "already in use\n"); } else ret = 0; if (chain_alloc) ocfs2_free_cached_inode(fs, chain_alloc); bail: return ret; }
static errcode_t empty_and_truncate_journal(ocfs2_filesys *fs, uint16_t removed_slot) { errcode_t ret; uint64_t blkno; ocfs2_cached_inode *ci = NULL; char fname[OCFS2_MAX_FILENAME_LEN]; ocfs2_sprintf_system_inode_name(fname, OCFS2_MAX_FILENAME_LEN, JOURNAL_SYSTEM_INODE, removed_slot); verbosef(VL_APP, "Truncating journal \"%s\"\n", fname); ret = ocfs2_lookup_system_inode(fs, JOURNAL_SYSTEM_INODE, removed_slot, &blkno); if (ret) { verbosef(VL_APP, "%s while looking up journal \"%s\"\n", error_message(ret), fname); goto bail; } ret = ocfs2_read_cached_inode(fs, blkno, &ci); if (ret) { verbosef(VL_APP, "%s while reading journal inode %"PRIu64"\n", error_message(ret), blkno); goto bail; } /* we have to empty the journal since it may contains some * inode blocks which look like valid(except the i_blkno). * So if this block range is used for future inode alloc * files, fsck.ocfs2 may raise some error. */ ret = empty_journal(fs, ci); if (ret) { verbosef(VL_APP, "%s while emptying journal \"%s\"\n", error_message(ret), fname); goto bail; } ret = ocfs2_truncate(fs, blkno, 0); if (ret) { verbosef(VL_APP, "%s while truncating journal \"%s\"\n", error_message(ret), fname); goto bail; } verbosef(VL_APP, "Journal \"%s\" truncated\n", fname); bail: if (ci) ocfs2_free_cached_inode(fs, ci); return ret; }
errcode_t ocfs2_extend_allocation(ocfs2_filesys *fs, uint64_t ino, uint32_t new_clusters) { errcode_t ret; ocfs2_cached_inode *ci = NULL; ret = ocfs2_read_cached_inode(fs, ino, &ci); if (ret) goto bail; ret = ocfs2_cached_inode_extend_allocation(ci, new_clusters); if (ret) goto bail; ret = ocfs2_write_cached_inode(fs, ci); bail: if (ci) ocfs2_free_cached_inode(fs, ci); return ret; }
/* * Insert an extent into an inode btree. */ errcode_t ocfs2_inode_insert_extent(ocfs2_filesys *fs, uint64_t ino, uint32_t cpos, uint64_t c_blkno, uint32_t clusters, uint16_t flag) { errcode_t ret; ocfs2_cached_inode *ci = NULL; ret = ocfs2_read_cached_inode(fs, ino, &ci); if (ret) goto bail; ret = ocfs2_cached_inode_insert_extent(ci, cpos, c_blkno, clusters, flag); if (ret) goto bail; ret = ocfs2_write_cached_inode(fs, ci); bail: if (ci) ocfs2_free_cached_inode(fs, ci); return ret; }
/* XXX care about zeroing new clusters and final partially truncated * clusters */ errcode_t ocfs2_truncate_full(ocfs2_filesys *fs, uint64_t ino, uint64_t new_i_size, errcode_t (*free_clusters)(ocfs2_filesys *fs, uint32_t len, uint64_t start, void *free_data), void *free_data) { errcode_t ret; uint32_t new_clusters; ocfs2_cached_inode *ci = NULL; ret = ocfs2_read_cached_inode(fs, ino, &ci); if (ret) goto out; /* in case of dio crashed, force do trucate since blocks may already * be allocated */ if (ci->ci_inode->i_flags & cpu_to_le32(OCFS2_DIO_ORPHANED_FL)) { ci->ci_inode->i_flags &= ~cpu_to_le32(OCFS2_DIO_ORPHANED_FL); ci->ci_inode->i_dio_orphaned_slot = 0; new_i_size = ci->ci_inode->i_size; goto truncate; } if (ci->ci_inode->i_size == new_i_size) goto out; if (ci->ci_inode->i_size < new_i_size) { ret = ocfs2_extend_file(fs, ino, new_i_size); goto out; } truncate: if ((S_ISLNK(ci->ci_inode->i_mode) && !ci->ci_inode->i_clusters) || (ci->ci_inode->i_dyn_features & OCFS2_INLINE_DATA_FL)) ret = ocfs2_truncate_inline(fs, ino, new_i_size); else { ret = ocfs2_zero_tail_and_truncate_full(fs, ci, new_i_size, &new_clusters, free_clusters, free_data); if (ret) goto out; ci->ci_inode->i_clusters = new_clusters; /* now all the clusters and extent blocks are freed. * only when the file's content is empty, should the tree depth * change. */ if (new_clusters == 0) ci->ci_inode->id2.i_list.l_tree_depth = 0; ci->ci_inode->i_size = new_i_size; ret = ocfs2_write_cached_inode(fs, ci); } if (!ret && !new_i_size && ci->ci_inode->i_refcount_loc && (ci->ci_inode->i_dyn_features & OCFS2_HAS_REFCOUNT_FL)) ret = ocfs2_detach_refcount_tree(fs, ino, ci->ci_inode->i_refcount_loc); out: if (ci) ocfs2_free_cached_inode(fs, ci); return ret; }
/* 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; }
/* * We only need to replay the journals if the inode's flag is set and s_start * indicates that there is actually pending data in the journals. * * In the simple case of an unclean shutdown we don't want to have to build up * enough state to be able to truncate the inodes waiting in the orphan dir. * ocfs2 in the kernel only fixes up the orphan dirs if the journal dirty flag * is set. So after replaying the journals we clear s_startin the journals to * stop a second journal replay but leave the dirty bit set so that the kernel * will truncate the orphaned inodes. */ errcode_t o2fsck_should_replay_journals(ocfs2_filesys *fs, int *should, int *has_dirty) { uint16_t i, max_slots; char *buf = NULL; uint64_t blkno; errcode_t ret; ocfs2_cached_inode *cinode = NULL; int is_dirty; uint64_t contig; journal_superblock_t *jsb; *should = 0; max_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) { com_err(whoami, ret, "while allocating room to read journal " "blocks"); goto out; } jsb = (journal_superblock_t *)buf; for (i = 0; i < max_slots; i++) { ret = ocfs2_lookup_system_inode(fs, JOURNAL_SYSTEM_INODE, i, &blkno); if (ret) { com_err(whoami, ret, "while looking up the journal " "inode for slot %d", i); goto out; } if (cinode) { ocfs2_free_cached_inode(fs, cinode); cinode = NULL; } ret = ocfs2_read_cached_inode(fs, blkno, &cinode); if (ret) { com_err(whoami, ret, "while reading cached inode " "%"PRIu64" for slot %d's journal", blkno, i); goto out; } is_dirty = cinode->ci_inode->id1.journal1.ij_flags & OCFS2_JOURNAL_DIRTY_FL; verbosef("slot %d JOURNAL_DIRTY_FL: %d\n", i, is_dirty); if (!is_dirty) continue; else *has_dirty = 1; ret = ocfs2_extent_map_get_blocks(cinode, 0, 1, &blkno, &contig, NULL); if (ret) { com_err(whoami, ret, "while looking up the journal " "super block in slot %d's journal", i); goto out; } /* XXX be smarter about reading in the whole super block if it * spans multiple blocks */ ret = ocfs2_read_journal_superblock(fs, blkno, buf); if (ret) { com_err(whoami, ret, "while reading the journal " "super block in slot %d's journal", i); goto out; } if (jsb->s_start) *should = 1; } out: if (buf) ocfs2_free(&buf); if (cinode) ocfs2_free_cached_inode(fs, cinode); return ret; }
errcode_t read_journal(ocfs2_filesys *fs, uint64_t blkno, FILE *out) { char *buf = NULL; char *jsb_buf = NULL; char *p; uint64_t blocknum; uint64_t len; uint64_t offset; uint32_t got; uint64_t last_unknown = 0; uint32_t buflen = 1024 * 1024; int buflenbits; ocfs2_cached_inode *ci = NULL; errcode_t ret; journal_superblock_t *jsb; ret = ocfs2_read_cached_inode(fs, blkno, &ci); if (ret) { com_err(gbls.cmd, ret, "while reading inode %"PRIu64, blkno); goto bail; } ret = ocfs2_malloc_block(fs->fs_io, &jsb_buf); if (ret) { com_err(gbls.cmd, ret, "while allocating journal superblock buffer"); goto bail; } buflenbits = buflen >> OCFS2_RAW_SB(gbls.fs->fs_super)->s_blocksize_bits; ret = ocfs2_malloc_blocks(fs->fs_io, buflenbits, &buf); if (ret) { com_err(gbls.cmd, ret, "while allocating %u bytes", buflen); goto bail; } offset = 0; blocknum = 0; jsb = (journal_superblock_t *)jsb_buf; while (1) { ret = ocfs2_file_read(ci, buf, buflen, offset, &got); if (ret) { com_err(gbls.cmd, ret, "while reading journal"); goto bail; }; if (got == 0) break; p = buf; len = got; if (offset == 0) { memcpy(jsb_buf, buf, fs->fs_blocksize); dump_jbd_superblock(out, jsb); ocfs2_swap_journal_superblock(jsb); blocknum++; p += fs->fs_blocksize; len -= fs->fs_blocksize; } scan_journal(out, jsb, p, len, &blocknum, &last_unknown); if (got < buflen) break; offset += got; } if (last_unknown) { dump_jbd_unknown(out, last_unknown, blocknum); last_unknown = 0; } bail: if (jsb_buf) ocfs2_free(&jsb_buf); if (buf) ocfs2_free(&buf); if (ci) ocfs2_free_cached_inode(fs, ci); return ret; }
static errcode_t ocfs2_file_block_write(ocfs2_cached_inode *ci, void *buf, uint32_t count, uint64_t offset, uint32_t *wrote) { ocfs2_filesys *fs = ci->ci_fs; errcode_t ret = 0; char *ptr = (char *) buf; uint32_t wanted_blocks; uint64_t contig_blocks; uint64_t v_blkno; uint64_t p_blkno, p_start, p_end; uint64_t begin_blocks = 0, end_blocks = 0; uint32_t tmp; uint64_t num_blocks; int bs_bits = OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits; uint64_t ino = ci->ci_blkno; uint32_t n_clusters, cluster_begin, cluster_end; uint64_t bpc = fs->fs_clustersize/fs->fs_blocksize; int insert = 0; uint16_t extent_flags = 0; /* o_direct requires aligned io */ tmp = fs->fs_blocksize - 1; if ((count & tmp) || (offset & (uint64_t)tmp) || ((unsigned long)ptr & tmp)) return OCFS2_ET_INVALID_ARGUMENT; wanted_blocks = count >> bs_bits; v_blkno = offset >> bs_bits; *wrote = 0; num_blocks = (ci->ci_inode->i_size + fs->fs_blocksize - 1) >> bs_bits; if (v_blkno >= num_blocks) return 0; if (v_blkno + wanted_blocks > num_blocks) wanted_blocks = (uint32_t) (num_blocks - v_blkno); while(wanted_blocks) { ret = ocfs2_extent_map_get_blocks(ci, v_blkno, 1, &p_blkno, &contig_blocks, &extent_flags); if (ret) return ret; if (contig_blocks > wanted_blocks) contig_blocks = wanted_blocks; begin_blocks = 0; end_blocks = 0; p_end = 0; if (!p_blkno) { /* * We meet with a hole here, so we allocate clusters * and empty the both ends in case. * * We will postpone the extent insertion after we * successfully write the extent block, so that and * problems happens in block writing would not affect * the file. */ cluster_begin = ocfs2_blocks_to_clusters(fs, v_blkno); cluster_end = ocfs2_blocks_to_clusters(fs, v_blkno + contig_blocks -1); n_clusters = cluster_end - cluster_begin + 1; ret = ocfs2_new_clusters(fs, 1, n_clusters, &p_start, &n_clusters); if (ret || n_clusters == 0) return ret; begin_blocks = v_blkno & (bpc - 1); p_blkno = p_start + begin_blocks; contig_blocks = n_clusters * bpc - begin_blocks; if (contig_blocks > wanted_blocks) { end_blocks = contig_blocks - wanted_blocks; contig_blocks = wanted_blocks; p_end = p_blkno + wanted_blocks; } insert = 1; } else if (extent_flags & OCFS2_EXT_UNWRITTEN) { begin_blocks = v_blkno & (bpc - 1); p_start = p_blkno - begin_blocks; p_end = p_blkno + wanted_blocks; end_blocks = (p_end & (bpc - 1)) ? bpc - (p_end & (bpc - 1 )) : 0; } if (begin_blocks) { /* * The user don't write the first blocks, * so we have to empty them. */ ret = empty_blocks(fs, p_start, begin_blocks); if (ret) return ret; } if (end_blocks) { /* * we don't need to write that many blocks, * so empty the blocks at the bottom. */ ret = empty_blocks(fs, p_end, end_blocks); if (ret) return ret; } ret = io_write_block(fs->fs_io, p_blkno, contig_blocks, ptr); if (ret) return ret; if (insert) { ret = ocfs2_cached_inode_insert_extent(ci, ocfs2_blocks_to_clusters(fs,v_blkno), p_start, n_clusters, 0); if (ret) { /* * XXX: We don't wan't to overwrite the error * from insert_extent(). But we probably need * to BE LOUDLY UPSET. */ ocfs2_free_clusters(fs, n_clusters, p_start); return ret; } /* save up what we have done. */ ret = ocfs2_write_cached_inode(fs, ci); if (ret) return ret; ret = ocfs2_extent_map_get_blocks(ci, v_blkno, 1, &p_blkno, NULL, NULL); /* now we shouldn't find a hole. */ if (!p_blkno || p_blkno != p_start + begin_blocks) ret = OCFS2_ET_INTERNAL_FAILURE; if (ret) return ret; insert = 0; } else if (extent_flags & OCFS2_EXT_UNWRITTEN) { cluster_begin = ocfs2_blocks_to_clusters(fs, v_blkno); cluster_end = ocfs2_blocks_to_clusters(fs, v_blkno + contig_blocks -1); n_clusters = cluster_end - cluster_begin + 1; ret = ocfs2_mark_extent_written(fs, ci->ci_inode, cluster_begin, n_clusters, p_blkno & ~(bpc - 1)); if (ret) return ret; ocfs2_free_cached_inode(fs, ci); ocfs2_read_cached_inode(fs,ino, &ci); } *wrote += (contig_blocks << bs_bits); wanted_blocks -= contig_blocks; if (wanted_blocks) { ptr += (contig_blocks << bs_bits); v_blkno += (uint64_t)contig_blocks; } else { if (*wrote + offset > ci->ci_inode->i_size) *wrote = (uint32_t) (ci->ci_inode->i_size - offset); /* break */ } } return ret; }
int main(int argc, char *argv[]) { errcode_t ret; uint64_t blkno, contig, blkoff = 0; uint16_t ext_flags; int count = 0; int c, op = 0; char *filename; ocfs2_filesys *fs; ocfs2_cached_inode *cinode; blkno = OCFS2_SUPER_BLOCK_BLKNO; initialize_ocfs_error_table(); while ((c = getopt(argc, argv, "i:b:")) != EOF) { switch (c) { case 'i': blkno = read_number(optarg); if (blkno <= OCFS2_SUPER_BLOCK_BLKNO) { fprintf(stderr, "Invalid inode block: %s\n", optarg); print_usage(); return 1; } break; case 'b': if (op) { fprintf(stderr, "Cannot specify more than one operation\n"); print_usage(); return 1; } if (read_b_numbers(optarg, &blkoff, &count)) { fprintf(stderr, "Invalid block range: %s\n", optarg); print_usage(); return 1; } op = OP_LOOKUP_BLOCK; break; default: print_usage(); return 1; break; } } if (!op) { fprintf(stderr, "Missing operation\n"); print_usage(); return 1; } if (optind >= argc) { fprintf(stderr, "Missing filename\n"); print_usage(); return 1; } filename = argv[optind]; ret = ocfs2_open(filename, OCFS2_FLAG_RO, 0, 0, &fs); if (ret) { com_err(argv[0], ret, "while opening file \"%s\"", filename); goto out; } ret = ocfs2_read_cached_inode(fs, blkno, &cinode); if (ret) { com_err(argv[0], ret, "while reading inode %"PRIu64, blkno); goto out_close; } fprintf(stdout, "OCFS2 inode %"PRIu64" on \"%s\" has depth %"PRId16"\n", blkno, filename, cinode->ci_inode->id2.i_list.l_tree_depth); ret = ocfs2_extent_map_get_blocks(cinode, blkoff, count, &blkno, &contig, &ext_flags); if (ret) { com_err(argv[0], ret, "looking up block range %"PRIu64":%d", blkoff, count); goto out_free; } fprintf(stdout, "Lookup of block range %"PRIu64":%d returned %"PRIu64":%"PRIu64"\n", blkoff, count, blkno, contig); out_free: ocfs2_free_cached_inode(fs, cinode); out_close: ret = ocfs2_close(fs); if (ret) { com_err(argv[0], ret, "while closing file \"%s\"", filename); } out: return 0; }
errcode_t ocfs2_allocate_unwritten_extents(ocfs2_filesys *fs, uint64_t ino, uint64_t offset, uint64_t len) { errcode_t ret = 0; uint32_t n_clusters = 0, cpos; uint64_t p_blkno = 0, v_blkno, v_end, contig_blocks, wanted_blocks; ocfs2_cached_inode *ci = NULL; if (!(fs->fs_flags & OCFS2_FLAG_RW)) return OCFS2_ET_RO_FILESYS; if (!ocfs2_writes_unwritten_extents(OCFS2_RAW_SB(fs->fs_super))) return OCFS2_ET_RO_UNSUPP_FEATURE; ret = ocfs2_read_cached_inode(fs, ino, &ci); if (ret) goto out; if (!(ci->ci_inode->i_flags & OCFS2_VALID_FL)) return OCFS2_ET_INODE_NOT_VALID; if (ci->ci_inode->i_flags & OCFS2_SYSTEM_FL) return OCFS2_ET_INVALID_ARGUMENT; if (!S_ISREG(ci->ci_inode->i_mode)) return OCFS2_ET_INVALID_ARGUMENT; v_blkno = offset / fs->fs_blocksize; v_end = (offset + len - 1) / fs->fs_blocksize; while (v_blkno <= v_end) { ret = ocfs2_extent_map_get_blocks(ci, v_blkno, 1, &p_blkno, &contig_blocks, NULL); if (ret) continue; if (p_blkno) { v_blkno += contig_blocks; continue; } /* * There is a hole, so we have to allocate the space and * insert the unwritten extents. */ wanted_blocks = ocfs2_min(contig_blocks, v_end - v_blkno + 1); n_clusters = ocfs2_clusters_in_blocks(fs, wanted_blocks); ret = ocfs2_new_clusters(fs, 1, n_clusters, &p_blkno, &n_clusters); if (ret || n_clusters == 0) break; cpos = ocfs2_blocks_to_clusters(fs, v_blkno); ret = ocfs2_cached_inode_insert_extent(ci, cpos, p_blkno, n_clusters, OCFS2_EXT_UNWRITTEN); if (ret) { /* * XXX: We don't wan't to overwrite the error * from insert_extent(). But we probably need * to BE LOUDLY UPSET. */ ocfs2_free_clusters(fs, n_clusters, p_blkno); goto out; } /* save up what we have done. */ ret = ocfs2_write_cached_inode(fs, ci); if (ret) goto out; v_blkno = ocfs2_clusters_to_blocks(fs, cpos + n_clusters); } if (ci->ci_inode->i_size <= offset + len) { ci->ci_inode->i_size = offset + len; ret = ocfs2_write_cached_inode(fs, ci); } out: if (ci) ocfs2_free_cached_inode(fs, ci); return ret; }