errcode_t ocfs2_cached_inode_extend_allocation(ocfs2_cached_inode *ci, uint32_t new_clusters) { errcode_t ret = 0; uint32_t n_clusters = 0, cpos; uint64_t blkno, file_size; ocfs2_filesys *fs = ci->ci_fs; file_size = ci->ci_inode->i_size; cpos = (file_size + fs->fs_clustersize - 1) / fs->fs_clustersize; while (new_clusters) { n_clusters = 1; ret = ocfs2_new_clusters(fs, 1, new_clusters, &blkno, &n_clusters); if (ret) break; ret = ocfs2_cached_inode_insert_extent(ci, cpos, blkno, 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, blkno); break; } new_clusters -= n_clusters; cpos += n_clusters; } return ret; }
static errcode_t create_local_alloc(ocfs2_filesys *fs, uint16_t slot) { errcode_t ret; char *buf = NULL; struct ocfs2_dinode *di; struct ocfs2_local_alloc *la; uint32_t la_size, found; uint64_t la_off, blkno; ret = ocfs2_lookup_system_inode(fs, LOCAL_ALLOC_SYSTEM_INODE, slot, &blkno); if (ret) goto bail; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) goto bail; ret = ocfs2_read_inode(fs, blkno, buf); if (ret) goto bail; di = (struct ocfs2_dinode *)buf; if (!(di->i_flags & OCFS2_VALID_FL)) goto bail; if (!(di->i_flags & OCFS2_LOCAL_ALLOC_FL)) goto bail; if (di->id1.bitmap1.i_total > 0) { fprintf(stderr, "local alloc#%"PRIu64" file not empty." "Can't create a new one.\n", blkno); goto bail; } la_size = get_local_alloc_window_bits(); ret = ocfs2_new_clusters(fs, 1, la_size, &la_off, &found); if (ret) goto bail; if(la_size != found) goto bail; la = &(di->id2.i_lab); la->la_bm_off = ocfs2_blocks_to_clusters(fs, la_off); di->id1.bitmap1.i_total = la_size; di->id1.bitmap1.i_used = 0; memset(la->la_bitmap, 0, la->la_size); ret = ocfs2_write_inode(fs, blkno, buf); bail: if(buf) ocfs2_free(&buf); return ret; }
static void create_local_alloc(ocfs2_filesys *fs, uint64_t blkno) { errcode_t ret; char *buf = NULL; struct ocfs2_dinode *di; struct ocfs2_local_alloc *la; uint32_t la_size, found; uint64_t la_off; 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"); if (di->id1.bitmap1.i_total > 0) { FSWRK_WARN("local alloc#%"PRIu64" file not empty." "Can't create a new one.\n", blkno); goto bail; } la_size = get_local_alloc_window_bits(); ret = ocfs2_new_clusters(fs, 1, la_size, &la_off, &found); if (ret) FSWRK_COM_FATAL(progname, ret); if(la_size != found) FSWRK_FATAL("can't allocate enough clusters for local alloc"); la = &(di->id2.i_lab); la->la_bm_off = la_off; di->id1.bitmap1.i_total = la_size; di->id1.bitmap1.i_used = 0; memset(la->la_bitmap, 0, la->la_size); ret = ocfs2_write_inode(fs, blkno, buf); if (ret) FSWRK_COM_FATAL(progname, ret); bail: if(buf) ocfs2_free(&buf); return; }
static void create_truncate_log(ocfs2_filesys *fs, uint64_t blkno, uint16_t used, uint32_t clusters) { errcode_t ret; char *buf = NULL; struct ocfs2_dinode *di; struct ocfs2_truncate_log *tl; uint16_t i, max; uint32_t found; uint64_t begin; max = ocfs2_truncate_recs_per_inode(fs->fs_blocksize); if (used > max) FSWRK_FATAL("recnum exceeds the limit of truncate log"); 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 valid file"); if (!(di->i_flags & OCFS2_DEALLOC_FL)) FSWRK_FATAL("not a valid truncate log"); tl = &di->id2.i_dealloc; if (tl->tl_used > 0) { FSWRK_WARN("truncate log#%"PRIu64" file not empty." "Can't create a new one.\n", blkno); goto bail; } used = min(used, tl->tl_count); tl->tl_used = used; for (i = 0; i < tl->tl_used; i++) { ret = ocfs2_new_clusters(fs, 1, clusters, &begin, &found); if (ret) FSWRK_COM_FATAL(progname, ret); tl->tl_recs[i].t_start = cpu_to_le32(ocfs2_blocks_to_clusters(fs, begin)); tl->tl_recs[i].t_clusters = cpu_to_le32(found); } ret = ocfs2_write_inode(fs, blkno, buf); if (ret) FSWRK_COM_FATAL(progname, ret); bail: if(buf) ocfs2_free(&buf); return; }
static errcode_t create_truncate_log(ocfs2_filesys *fs, uint16_t slot) { errcode_t ret; char *buf = NULL; struct ocfs2_dinode *di; struct ocfs2_truncate_log *tl; uint16_t i, used = 10; uint32_t found, clusters = 10; uint64_t begin, blkno; ret = ocfs2_lookup_system_inode(fs, TRUNCATE_LOG_SYSTEM_INODE, slot, &blkno); if (ret) goto bail; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) goto bail; ret = ocfs2_read_inode(fs, blkno, buf); if (ret) goto bail; di = (struct ocfs2_dinode *)buf; if (!(di->i_flags & OCFS2_VALID_FL)) { fprintf(stderr,"not a valid file\n"); goto bail; } if (!(di->i_flags & OCFS2_DEALLOC_FL)) { fprintf(stderr,"not a valid truncate log\n"); goto bail; } tl = &di->id2.i_dealloc; if (le16_to_cpu(tl->tl_used) > 0) { fprintf(stderr,"truncate log#%"PRIu64" file not empty." "Can't create a new one.\n", blkno); goto bail; } tl->tl_used = used; for (i = 0; i < tl->tl_used; i++) { ret = ocfs2_new_clusters(fs, 1, clusters, &begin, &found); if (ret) goto bail; tl->tl_recs[i].t_start = ocfs2_blocks_to_clusters(fs, begin); tl->tl_recs[i].t_clusters = found; } ret = ocfs2_write_inode(fs, blkno, buf); bail: if(buf) ocfs2_free(&buf); return ret; }
errcode_t ocfs2_convert_inline_data_to_extents(ocfs2_cached_inode *ci) { errcode_t ret; uint32_t bytes, n_clusters; uint64_t p_start; char *inline_data = NULL; struct ocfs2_dinode *di = ci->ci_inode; ocfs2_filesys *fs = ci->ci_fs; uint64_t bpc = fs->fs_clustersize/fs->fs_blocksize; unsigned int new_size; if (di->i_size) { ret = ocfs2_malloc_block(fs->fs_io, &inline_data); if (ret) goto out; ret = ocfs2_inline_data_read(di, inline_data, fs->fs_blocksize, 0, &bytes); if (ret) goto out; } ocfs2_dinode_new_extent_list(fs, di); di->i_dyn_features &= ~OCFS2_INLINE_DATA_FL; ret = ocfs2_new_clusters(fs, 1, 1, &p_start, &n_clusters); if (ret || n_clusters == 0) goto out; ret = empty_blocks(fs, p_start, bpc); if (ret) goto out; if (di->i_size) { if (S_ISDIR(di->i_mode)) { if (ocfs2_supports_dir_trailer(fs)) new_size = ocfs2_dir_trailer_blk_off(fs); else new_size = fs->fs_blocksize; ocfs2_expand_last_dirent(inline_data, di->i_size, new_size); if (ocfs2_supports_dir_trailer(fs)) ocfs2_init_dir_trailer(fs, di, p_start, inline_data); di->i_size = fs->fs_blocksize; ret = ocfs2_write_dir_block(fs, di, p_start, inline_data); } else ret = io_write_block(fs->fs_io, p_start, 1, inline_data); if (ret) goto out; } ret = ocfs2_cached_inode_insert_extent(ci, 0, p_start, n_clusters, 0); if (ret) goto out; ret = ocfs2_write_cached_inode(fs, ci); out: if (inline_data) ocfs2_free(&inline_data); 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; }
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; }