Currently the breadn_flags() and getblkx() interfaces are passed

the vnode, logical block number, and size of data block that is
being requested. They then use the VOP_BMAP function to calculate
the mapping from logical block number to physical block number from
which to access the data. This change expands the interface to also
pass the physical block number in cases where the VOP_MAP function
may no longer work, for example when a file is being truncated.

No functional change.

Reviewed by:  kib
Tested by:    Peter Holm
Sponsored by: Netflix
This commit is contained in:
Kirk McKusick 2019-12-03 23:07:09 +00:00
parent ddef7bb56f
commit d00066a5f9
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=355371
7 changed files with 56 additions and 69 deletions

View File

@ -2126,10 +2126,17 @@ breada(struct vnode * vp, daddr_t * rablkno, int * rabsize, int cnt,
* getblk(). Also starts asynchronous I/O on read-ahead blocks.
*
* Always return a NULL buffer pointer (in bpp) when returning an error.
*
* The blkno parameter is the logical block being requested. Normally
* the mapping of logical block number to disk block address is done
* by calling VOP_BMAP(). However, if the mapping is already known, the
* disk block address can be passed using the dblkno parameter. If the
* disk block address is not known, then the same value should be passed
* for blkno and dblkno.
*/
int
breadn_flags(struct vnode *vp, daddr_t blkno, int size, daddr_t *rablkno,
int *rabsize, int cnt, struct ucred *cred, int flags,
breadn_flags(struct vnode *vp, daddr_t blkno, daddr_t dblkno, int size,
daddr_t *rablkno, int *rabsize, int cnt, struct ucred *cred, int flags,
void (*ckhashfunc)(struct buf *), struct buf **bpp)
{
struct buf *bp;
@ -2142,11 +2149,14 @@ breadn_flags(struct vnode *vp, daddr_t blkno, int size, daddr_t *rablkno,
* Can only return NULL if GB_LOCK_NOWAIT or GB_SPARSE flags
* are specified.
*/
error = getblkx(vp, blkno, size, 0, 0, flags, &bp);
error = getblkx(vp, blkno, dblkno, size, 0, 0, flags, &bp);
if (error != 0) {
*bpp = NULL;
return (error);
}
KASSERT(blkno == bp->b_lblkno,
("getblkx returned buffer for blkno %jd instead of blkno %jd",
(intmax_t)bp->b_lblkno, (intmax_t)blkno));
flags &= ~GB_NOSPARSE;
*bpp = bp;
@ -3791,7 +3801,7 @@ getblk(struct vnode *vp, daddr_t blkno, int size, int slpflag, int slptimeo,
struct buf *bp;
int error;
error = getblkx(vp, blkno, size, slpflag, slptimeo, flags, &bp);
error = getblkx(vp, blkno, blkno, size, slpflag, slptimeo, flags, &bp);
if (error != 0)
return (NULL);
return (bp);
@ -3819,7 +3829,7 @@ getblk(struct vnode *vp, daddr_t blkno, int size, int slpflag, int slptimeo,
* case it is returned with B_INVAL clear and B_CACHE set based on the
* backing VM.
*
* getblk() also forces a bwrite() for any B_DELWRI buffer whos
* getblk() also forces a bwrite() for any B_DELWRI buffer whose
* B_CACHE bit is clear.
*
* What this means, basically, is that the caller should use B_CACHE to
@ -3832,10 +3842,17 @@ getblk(struct vnode *vp, daddr_t blkno, int size, int slpflag, int slptimeo,
* a write attempt or if it was a successful read. If the caller
* intends to issue a READ, the caller must clear B_INVAL and BIO_ERROR
* prior to issuing the READ. biodone() will *not* clear B_INVAL.
*
* The blkno parameter is the logical block being requested. Normally
* the mapping of logical block number to disk block address is done
* by calling VOP_BMAP(). However, if the mapping is already known, the
* disk block address can be passed using the dblkno parameter. If the
* disk block address is not known, then the same value should be passed
* for blkno and dblkno.
*/
int
getblkx(struct vnode *vp, daddr_t blkno, int size, int slpflag, int slptimeo,
int flags, struct buf **bpp)
getblkx(struct vnode *vp, daddr_t blkno, daddr_t dblkno, int size, int slpflag,
int slptimeo, int flags, struct buf **bpp)
{
struct buf *bp;
struct bufobj *bo;
@ -3854,7 +3871,7 @@ getblkx(struct vnode *vp, daddr_t blkno, int size, int slpflag, int slptimeo,
flags &= ~(GB_UNMAPPED | GB_KVAALLOC);
bo = &vp->v_bufobj;
d_blkno = blkno;
d_blkno = dblkno;
loop:
BO_RLOCK(bo);
bp = gbincore(bo, blkno);

View File

@ -131,7 +131,7 @@ cluster_read(struct vnode *vp, u_quad_t filesize, daddr_t lblkno, long size,
/*
* get the requested block
*/
error = getblkx(vp, lblkno, size, 0, 0, gbflags, &bp);
error = getblkx(vp, lblkno, lblkno, size, 0, 0, gbflags, &bp);
if (error != 0) {
*bpp = NULL;
return (error);

View File

@ -520,15 +520,16 @@ int buf_dirty_count_severe(void);
void bremfree(struct buf *);
void bremfreef(struct buf *); /* XXX Force bremfree, only for nfs. */
#define bread(vp, blkno, size, cred, bpp) \
breadn_flags(vp, blkno, size, NULL, NULL, 0, cred, 0, NULL, bpp)
breadn_flags(vp, blkno, blkno, size, NULL, NULL, 0, cred, 0, \
NULL, bpp)
#define bread_gb(vp, blkno, size, cred, gbflags, bpp) \
breadn_flags(vp, blkno, size, NULL, NULL, 0, cred, \
breadn_flags(vp, blkno, blkno, size, NULL, NULL, 0, cred, \
gbflags, NULL, bpp)
#define breadn(vp, blkno, size, rablkno, rabsize, cnt, cred, bpp) \
breadn_flags(vp, blkno, size, rablkno, rabsize, cnt, cred, \
breadn_flags(vp, blkno, blkno, size, rablkno, rabsize, cnt, cred, \
0, NULL, bpp)
int breadn_flags(struct vnode *, daddr_t, int, daddr_t *, int *, int,
struct ucred *, int, void (*)(struct buf *), struct buf **);
int breadn_flags(struct vnode *, daddr_t, daddr_t, int, daddr_t *, int *,
int, struct ucred *, int, void (*)(struct buf *), struct buf **);
void bdwrite(struct buf *);
void bawrite(struct buf *);
void babarrierwrite(struct buf *);
@ -544,8 +545,8 @@ void vfs_busy_pages_release(struct buf *bp);
struct buf *incore(struct bufobj *, daddr_t);
struct buf *gbincore(struct bufobj *, daddr_t);
struct buf *getblk(struct vnode *, daddr_t, int, int, int, int);
int getblkx(struct vnode *vp, daddr_t blkno, int size, int slpflag,
int slptimeo, int flags, struct buf **bpp);
int getblkx(struct vnode *vp, daddr_t blkno, daddr_t dblkno, int size,
int slpflag, int slptimeo, int flags, struct buf **bpp);
struct buf *geteblk(int, int);
int bufwait(struct buf *);
int bufwrite(struct buf *);

View File

@ -2955,16 +2955,19 @@ ffs_getcg(fs, devvp, cg, flags, bpp, cgpp)
struct buf *bp;
struct cg *cgp;
const struct statfs *sfs;
daddr_t blkno;
int error;
*bpp = NULL;
*cgpp = NULL;
if ((fs->fs_metackhash & CK_CYLGRP) != 0)
flags |= GB_CKHASH;
error = breadn_flags(devvp, devvp->v_type == VREG ?
fragstoblks(fs, cgtod(fs, cg)) : fsbtodb(fs, cgtod(fs, cg)),
(int)fs->fs_cgsize, NULL, NULL, 0, NOCRED, flags,
ffs_ckhash_cg, &bp);
if (devvp->v_type == VREG)
blkno = fragstoblks(fs, cgtod(fs, cg));
else
blkno = fsbtodb(fs, cgtod(fs, cg));
error = breadn_flags(devvp, blkno, blkno, (int)fs->fs_cgsize, NULL,
NULL, 0, NOCRED, flags, ffs_ckhash_cg, &bp);
if (error != 0)
return (error);
cgp = (struct cg *)bp->b_data;

View File

@ -678,34 +678,14 @@ ffs_indirtrunc(ip, lbn, dbn, lastbn, level, countp)
* Get buffer of block pointers, zero those entries corresponding
* to blocks to be free'd, and update on disk copy first. Since
* double(triple) indirect before single(double) indirect, calls
* to bmap on these blocks will fail. However, we already have
* the on disk address, so we have to set the b_blkno field
* explicitly instead of letting bread do everything for us.
* to VOP_BMAP() on these blocks will fail. However, we already
* have the on-disk address, so we just pass it to bread() instead
* of having bread() attempt to calculate it using VOP_BMAP().
*/
vp = ITOV(ip);
bp = getblk(vp, lbn, (int)fs->fs_bsize, 0, 0, 0);
if ((bp->b_flags & B_CACHE) == 0) {
#ifdef RACCT
if (racct_enable) {
PROC_LOCK(curproc);
racct_add_buf(curproc, bp, 0);
PROC_UNLOCK(curproc);
}
#endif /* RACCT */
curthread->td_ru.ru_inblock++; /* pay for read */
bp->b_iocmd = BIO_READ;
bp->b_flags &= ~B_INVAL;
bp->b_ioflags &= ~BIO_ERROR;
if (bp->b_bcount > bp->b_bufsize)
panic("ffs_indirtrunc: bad buffer size");
bp->b_blkno = dbn;
vfs_busy_pages(bp, 0);
bp->b_iooffset = dbtob(bp->b_blkno);
bstrategy(bp);
error = bufwait(bp);
}
error = breadn_flags(vp, lbn, dbn, (int)fs->fs_bsize, NULL, NULL, 0,
NOCRED, 0, NULL, &bp);
if (error) {
brelse(bp);
*countp = 0;
return (error);
}

View File

@ -6294,29 +6294,15 @@ setup_trunc_indir(freeblks, ip, lbn, lastlbn, blkno)
return (0);
mp = freeblks->fb_list.wk_mp;
ump = VFSTOUFS(mp);
bp = getblk(ITOV(ip), lbn, mp->mnt_stat.f_iosize, 0, 0, 0);
if ((bp->b_flags & B_CACHE) == 0) {
bp->b_blkno = blkptrtodb(VFSTOUFS(mp), blkno);
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 /* RACCT */
curthread->td_ru.ru_inblock++;
error = bufwait(bp);
if (error) {
brelse(bp);
return (error);
}
}
/*
* Here, calls to VOP_BMAP() will fail. However, we already have
* the on-disk address, so we just pass it to bread() instead of
* having bread() attempt to calculate it using VOP_BMAP().
*/
error = breadn_flags(ITOV(ip), lbn, blkptrtodb(ump, blkno),
(int)mp->mnt_stat.f_iosize, NULL, NULL, 0, NOCRED, 0, NULL, &bp);
if (error)
return (error);
level = lbn_level(lbn);
lbnadd = lbn_offset(ump->um_fs, level);
/*

View File

@ -603,7 +603,7 @@ ffs_read(ap)
* the 6th argument.
*/
u_int nextsize = blksize(fs, ip, nextlbn);
error = breadn_flags(vp, lbn, size, &nextlbn,
error = breadn_flags(vp, lbn, lbn, size, &nextlbn,
&nextsize, 1, NOCRED, bflag, NULL, &bp);
} else {
/*