Add a EXT2FS-specific implementation for lseek(SEEK_DATA).
The lseek(SEEK_DATA) optimization logic could be simply borrowed from ufs side. See, https://reviews.freebsd.org/D19599. Reviewed by: pfg MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D23605
This commit is contained in:
parent
56cd269eac
commit
3767ed5b11
@ -139,6 +139,47 @@ ext4_bmapext(struct vnode *vp, int32_t bn, int64_t *bnp, int *runp, int *runb)
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
readindir(struct vnode *vp, e2fs_lbn_t lbn, e2fs_daddr_t daddr, struct buf **bpp)
|
||||
{
|
||||
struct buf *bp;
|
||||
struct mount *mp;
|
||||
struct ext2mount *ump;
|
||||
int error;
|
||||
|
||||
mp = vp->v_mount;
|
||||
ump = VFSTOEXT2(mp);
|
||||
|
||||
bp = getblk(vp, lbn, mp->mnt_stat.f_iosize, 0, 0, 0);
|
||||
if ((bp->b_flags & B_CACHE) == 0) {
|
||||
KASSERT(daddr != 0,
|
||||
("readindir: indirect block not in cache"));
|
||||
|
||||
bp->b_blkno = blkptrtodb(ump, daddr);
|
||||
bp->b_iocmd = BIO_READ;
|
||||
bp->b_flags &= ~B_INVAL;
|
||||
bp->b_ioflags &= ~BIO_ERROR;
|
||||
vfs_busy_pages(bp, 0);
|
||||
bp->b_iooffset = dbtob(bp->b_blkno);
|
||||
bstrategy(bp);
|
||||
#ifdef RACCT
|
||||
if (racct_enable) {
|
||||
PROC_LOCK(curproc);
|
||||
racct_add_buf(curproc, bp, 0);
|
||||
PROC_UNLOCK(curproc);
|
||||
}
|
||||
#endif
|
||||
curthread->td_ru.ru_inblock++;
|
||||
error = bufwait(bp);
|
||||
if (error != 0) {
|
||||
brelse(bp);
|
||||
return (error);
|
||||
}
|
||||
}
|
||||
*bpp = bp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Indirect blocks are now on the vnode for the file. They are given negative
|
||||
* logical block numbers. Indirect blocks are addressed by the negative
|
||||
@ -228,34 +269,9 @@ ext2_bmaparray(struct vnode *vp, daddr_t bn, daddr_t *bnp, int *runp, int *runb)
|
||||
*/
|
||||
if (bp)
|
||||
bqrelse(bp);
|
||||
|
||||
bp = getblk(vp, metalbn, bsize, 0, 0, 0);
|
||||
if ((bp->b_flags & B_CACHE) == 0) {
|
||||
#ifdef INVARIANTS
|
||||
if (!daddr)
|
||||
panic("ext2_bmaparray: indirect block not in cache");
|
||||
#endif
|
||||
bp->b_blkno = blkptrtodb(ump, daddr);
|
||||
bp->b_iocmd = BIO_READ;
|
||||
bp->b_flags &= ~B_INVAL;
|
||||
bp->b_ioflags &= ~BIO_ERROR;
|
||||
vfs_busy_pages(bp, 0);
|
||||
bp->b_iooffset = dbtob(bp->b_blkno);
|
||||
bstrategy(bp);
|
||||
#ifdef RACCT
|
||||
if (racct_enable) {
|
||||
PROC_LOCK(curproc);
|
||||
racct_add_buf(curproc, bp, 0);
|
||||
PROC_UNLOCK(curproc);
|
||||
}
|
||||
#endif
|
||||
curthread->td_ru.ru_inblock++;
|
||||
error = bufwait(bp);
|
||||
if (error) {
|
||||
brelse(bp);
|
||||
return (error);
|
||||
}
|
||||
}
|
||||
error = readindir(vp, metalbn, daddr, &bp);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
daddr = ((e2fs_daddr_t *)bp->b_data)[ap->in_off];
|
||||
if (num == 1 && daddr && runp) {
|
||||
@ -296,6 +312,107 @@ ext2_bmaparray(struct vnode *vp, daddr_t bn, daddr_t *bnp, int *runp, int *runb)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static e2fs_lbn_t
|
||||
lbn_count(struct ext2mount *ump, int level)
|
||||
|
||||
{
|
||||
e2fs_lbn_t blockcnt;
|
||||
|
||||
for (blockcnt = 1; level > 0; level--)
|
||||
blockcnt *= MNINDIR(ump);
|
||||
return (blockcnt);
|
||||
}
|
||||
|
||||
int
|
||||
ext2_bmap_seekdata(struct vnode *vp, off_t *offp)
|
||||
{
|
||||
struct buf *bp;
|
||||
struct indir a[EXT2_NIADDR + 1], *ap;
|
||||
struct inode *ip;
|
||||
struct mount *mp;
|
||||
struct ext2mount *ump;
|
||||
e2fs_daddr_t bn, daddr, nextbn;
|
||||
uint64_t bsize;
|
||||
off_t numblks;
|
||||
int error, num, num1, off;
|
||||
|
||||
bp = NULL;
|
||||
error = 0;
|
||||
ip = VTOI(vp);
|
||||
mp = vp->v_mount;
|
||||
ump = VFSTOEXT2(mp);
|
||||
|
||||
if (vp->v_type != VREG || (ip->i_flags & SF_SNAPSHOT) != 0)
|
||||
return (EINVAL);
|
||||
if (*offp < 0 || *offp >= ip->i_size)
|
||||
return (ENXIO);
|
||||
|
||||
bsize = mp->mnt_stat.f_iosize;
|
||||
for (bn = *offp / bsize, numblks = howmany(ip->i_size, bsize);
|
||||
bn < numblks; bn = nextbn) {
|
||||
if (bn < EXT2_NDADDR) {
|
||||
daddr = ip->i_db[bn];
|
||||
if (daddr != 0)
|
||||
break;
|
||||
nextbn = bn + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
ap = a;
|
||||
error = ext2_getlbns(vp, bn, ap, &num);
|
||||
if (error != 0)
|
||||
break;
|
||||
MPASS(num >= 2);
|
||||
daddr = ip->i_ib[ap->in_off];
|
||||
ap++, num--;
|
||||
for (nextbn = EXT2_NDADDR, num1 = num - 1; num1 > 0; num1--)
|
||||
nextbn += lbn_count(ump, num1);
|
||||
if (daddr == 0) {
|
||||
nextbn += lbn_count(ump, num);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (; daddr != 0 && num > 0; ap++, num--) {
|
||||
if (bp != NULL)
|
||||
bqrelse(bp);
|
||||
error = readindir(vp, ap->in_lbn, daddr, &bp);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* Scan the indirect block until we find a non-zero
|
||||
* pointer.
|
||||
*/
|
||||
off = ap->in_off;
|
||||
do {
|
||||
daddr = ((e2fs_daddr_t *)bp->b_data)[off];
|
||||
} while (daddr == 0 && ++off < MNINDIR(ump));
|
||||
nextbn += off * lbn_count(ump, num - 1);
|
||||
|
||||
/*
|
||||
* We need to recompute the LBNs of indirect
|
||||
* blocks, so restart with the updated block offset.
|
||||
*/
|
||||
if (off != ap->in_off)
|
||||
break;
|
||||
}
|
||||
if (num == 0) {
|
||||
/*
|
||||
* We found a data block.
|
||||
*/
|
||||
bn = nextbn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bp != NULL)
|
||||
bqrelse(bp);
|
||||
if (bn >= numblks)
|
||||
error = ENXIO;
|
||||
if (error == 0 && *offp < bn * bsize)
|
||||
*offp = bn * bsize;
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create an array of logical block number/offset pairs which represent the
|
||||
* path of indirect blocks required to access a data block. The first "pair"
|
||||
|
@ -64,6 +64,7 @@ e4fs_daddr_t ext2_blkpref(struct inode *, e2fs_lbn_t, int, e2fs_daddr_t *,
|
||||
int ext2_bmap(struct vop_bmap_args *);
|
||||
int ext2_bmaparray(struct vnode *, daddr_t, daddr_t *, int *, int *);
|
||||
int ext4_bmapext(struct vnode *, int32_t, int64_t *, int *, int *);
|
||||
int ext2_bmap_seekdata(struct vnode *, off_t *);
|
||||
void ext2_clusteracct(struct m_ext2fs *, char *, int, e4fs_daddr_t, int);
|
||||
void ext2_dirbad(struct inode *ip, doff_t offset, char *how);
|
||||
int ext2_ei2i(struct ext2fs_dinode *, struct inode *);
|
||||
|
@ -2157,11 +2157,24 @@ ext2_read(struct vop_read_args *ap)
|
||||
static int
|
||||
ext2_ioctl(struct vop_ioctl_args *ap)
|
||||
{
|
||||
struct vnode *vp;
|
||||
int error;
|
||||
|
||||
vp = ap->a_vp;
|
||||
switch (ap->a_command) {
|
||||
case FIOSEEKDATA:
|
||||
if (!(VTOI(vp)->i_flag & IN_E4EXTENTS)) {
|
||||
error = vn_lock(vp, LK_SHARED);
|
||||
if (error == 0) {
|
||||
error = ext2_bmap_seekdata(vp,
|
||||
(off_t *)ap->a_data);
|
||||
VOP_UNLOCK(vp);
|
||||
} else
|
||||
error = EBADF;
|
||||
return (error);
|
||||
}
|
||||
case FIOSEEKHOLE:
|
||||
return (vn_bmap_seekhole(ap->a_vp, ap->a_command,
|
||||
return (vn_bmap_seekhole(vp, ap->a_command,
|
||||
(off_t *)ap->a_data, ap->a_cred));
|
||||
default:
|
||||
return (ENOTTY);
|
||||
|
Loading…
x
Reference in New Issue
Block a user