/* * This function converts the logical block number of a file to * its physical block number on the disk within ext4 extents. */ static int ext4_bmapext(struct vnode *vp, int32_t bn, int64_t *bnp, int *runp, int *runb) { struct inode *ip; struct m_ext2fs *fs; struct ext4_extent *ep; struct ext4_extent_path path; daddr_t lbn; ip = VTOI(vp); fs = ip->i_e2fs; lbn = bn; /* * TODO: need to implement read ahead to improve the performance. */ if (runp != NULL) *runp = 0; if (runb != NULL) *runb = 0; ext4_ext_find_extent(fs, ip, lbn, &path); ep = path.ep_ext; if (ep == NULL) return (EIO); *bnp = fsbtodb(fs, lbn - ep->e_blk + (ep->e_start_lo | (daddr_t)ep->e_start_hi << 32)); if (*bnp == 0) *bnp = -1; return (0); }
/* * Logical block number of a file -> physical block number on disk within ext4 extents. */ int ext4_bmapext(struct vnode *vp, daddr_t bn, daddr_t *bnp, struct indir *ap, int *nump, int *runp) { struct inode *ip; struct m_ext2fs *fs; struct ext4_extent *ep; struct ext4_extent_path path; daddr_t pos; ip = VTOI(vp); fs = ip->i_e2fs; if (runp != NULL) *runp = 0; if (nump != NULL) *nump = 0; ext4_ext_find_extent(fs, ip, bn, &path); if ((ep = path.ep_ext) == NULL) return (EIO); pos = bn - ep->e_blk + (((daddr_t)ep->e_start_hi << 32) | ep->e_start_lo); if ((*bnp = fsbtodb(fs, pos)) == 0) *bnp = -1; return (0); }
static int finish_range(handle_t *handle, struct inode *inode, struct migrate_struct *lb) { int retval = 0, needed; struct ext4_extent newext; struct ext4_ext_path *path; if (lb->first_pblock == 0) return 0; /* Add the extent to temp inode*/ newext.ee_block = cpu_to_le32(lb->first_block); newext.ee_len = cpu_to_le16(lb->last_block - lb->first_block + 1); ext4_ext_store_pblock(&newext, lb->first_pblock); path = ext4_ext_find_extent(inode, lb->first_block, NULL); if (IS_ERR(path)) { retval = PTR_ERR(path); path = NULL; goto err_out; } /* * Calculate the credit needed to inserting this extent * Since we are doing this in loop we may accumalate extra * credit. But below we try to not accumalate too much * of them by restarting the journal. */ needed = ext4_ext_calc_credits_for_single_extent(inode, lb->last_block - lb->first_block + 1, path); /* * Make sure the credit we accumalated is not really high */ if (needed && ext4_handle_has_enough_credits(handle, EXT4_RESERVE_TRANS_BLOCKS)) { retval = ext4_journal_restart(handle, needed); if (retval) goto err_out; } else if (needed) { retval = ext4_journal_extend(handle, needed); if (retval) { /* * IF not able to extend the journal restart the journal */ retval = ext4_journal_restart(handle, needed); if (retval) goto err_out; } } retval = ext4_ext_insert_extent(handle, inode, path, &newext, 0); err_out: if (path) { ext4_ext_drop_refs(path); kfree(path); } lb->first_pblock = 0; return retval; }
/* * Convert the logical block number of a file to its physical block number * on the disk within ext4 extents. */ static int ext4_bmapext(struct vnode *vp, int32_t bn, int64_t *bnp, int *runp, int *runb) { struct inode *ip; struct m_ext2fs *fs; struct ext4_extent *ep; struct ext4_extent_path path = { .ep_bp = NULL }; daddr_t lbn; int error; ip = VTOI(vp); fs = ip->i_e2fs; lbn = bn; if (runp != NULL) *runp = 0; if (runb != NULL) *runb = 0; error = 0; ext4_ext_find_extent(fs, ip, lbn, &path); if (path.ep_is_sparse) { *bnp = -1; if (runp != NULL) *runp = path.ep_sparse_ext.e_len - (lbn - path.ep_sparse_ext.e_blk) - 1; if (runb != NULL) *runb = lbn - path.ep_sparse_ext.e_blk; } else { if (path.ep_ext == NULL) { error = EIO; goto out; } ep = path.ep_ext; *bnp = fsbtodb(fs, lbn - ep->e_blk + (ep->e_start_lo | (daddr_t)ep->e_start_hi << 32)); if (*bnp == 0) *bnp = -1; if (runp != NULL) *runp = ep->e_len - (lbn - ep->e_blk) - 1; if (runb != NULL) *runb = lbn - ep->e_blk; } out: if (path.ep_bp != NULL) brelse(path.ep_bp); return (error); }
/* * this function handles ext4 extents block mapping */ static int ext4_ext_read(struct vop_read_args *ap) { struct vnode *vp; struct inode *ip; struct uio *uio; struct m_ext2fs *fs; struct buf *bp; struct ext4_extent nex, *ep; struct ext4_extent_header *ehp; struct ext4_extent_path path; daddr_t lbn, nextlbn, newblk = 0; off_t bytesinfile; u_short mode; int cache_type; int orig_resid; int error = 0; int depth = 0; long size, xfersize, blkoffset; vp = ap->a_vp; ip = VTOI(vp); mode = ip->i_mode; uio = ap->a_uio; memset(&path, 0, sizeof(path)); orig_resid = uio->uio_resid; KASSERT(orig_resid >= 0, ("ext2_read: uio->uio_resid < 0")); if (orig_resid == 0) return (0); KASSERT(uio->uio_offset >= 0, ("ext2_read: uio->uio_offset < 0")); fs = ip->I_FS; if (uio->uio_offset < ip->i_size && uio->uio_offset >= fs->e2fs_maxfilesize) return (EOVERFLOW); for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) { if ((bytesinfile = ip->i_size - uio->uio_offset) <= 0) break; lbn = lblkno(fs, uio->uio_offset); nextlbn = lbn + 1; size = BLKSIZE(fs, ip, lbn); blkoffset = blkoff(fs, uio->uio_offset); xfersize = fs->e2fs_fsize - blkoffset; if (uio->uio_resid < xfersize) xfersize = uio->uio_resid; if (bytesinfile < xfersize) xfersize = bytesinfile; /* get block from ext4 extent cache */ cache_type = ext4_ext_in_cache(ip, lbn, &nex); if (cache_type != 0) { /* block does not be allocated yet */ if (cache_type == EXT4_EXT_CACHE_GAP) return (error); else if (cache_type == EXT4_EXT_CACHE_IN) newblk = lbn - nex.e_blk + (nex.e_start_lo | ((daddr_t)(nex.e_start_hi) << 31) << 1); } else { ext4_ext_find_extent(fs, ip, lbn, &path); depth = ((struct ext4_extent_header *)(ip->i_db))->eh_depth; if (path.ep_ext == NULL && depth != 0) return (EIO); ehp = path.ep_header; ep = path.ep_ext; if (ep == NULL) return (EIO); ext4_ext_put_cache(ip, ep, EXT4_EXT_CACHE_IN); newblk = lbn - ep->e_blk + (ep->e_start_lo | ((daddr_t)(ep->e_start_hi) << 31) << 1); if (path.ep_bp != NULL) { brelse(path.ep_bp); path.ep_bp = NULL; } } error = bread(ip->i_devvp, fsbtodb(fs, newblk), size, NOCRED, &bp); if (error) { brelse(bp); bp = NULL; break; } size -= bp->b_resid; if (size < xfersize) { if (size == 0) break; xfersize = size; } error = uiomove((char *)bp->b_data + blkoffset, (int)xfersize, uio); if (error) break; bqrelse(bp); } if (bp != NULL) bqrelse(bp); return (error); }