diff --git a/sys/fs/msdosfs/msdosfs_denode.c b/sys/fs/msdosfs/msdosfs_denode.c --- a/sys/fs/msdosfs/msdosfs_denode.c +++ b/sys/fs/msdosfs/msdosfs_denode.c @@ -428,11 +428,12 @@ if ((boff = length & pmp->pm_crbomask) != 0) { if (isadir) { bn = cntobn(pmp, eofentry); - error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, + error = breadb(pmp->pm_devvp, bntolbn(pmp, bn), bn, pmp->pm_bpcluster, NOCRED, &bp); } else { - error = bread(DETOV(dep), de_cluster(pmp, length), - pmp->pm_bpcluster, cred, &bp); + bn = de_cluster(pmp, length); + error = breadb(DETOV(dep), bntolbn(pmp, bn), bn, pmp->pm_bpcluster, + cred, &bp); } if (error) { #ifdef MSDOSFS_DEBUG @@ -503,6 +504,7 @@ struct msdosfsmount *pmp = dep->de_pmp; struct vnode *vp = DETOV(dep); struct buf *bp; + daddr_t bn; off_t eof_clusteroff; u_long count; int error; @@ -547,7 +549,8 @@ * actual buffer content which might exist in the tail of the * already valid cluster. */ - error = bread(vp, de_cluster(pmp, dep->de_FileSize), pmp->pm_bpcluster, + bn = de_cluster(pmp, dep->de_FileSize); + error = breadb(vp, bntolbn(pmp, bn), bn, pmp->pm_bpcluster, NOCRED, &bp); if (error != 0) goto rewind; diff --git a/sys/fs/msdosfs/msdosfs_fat.c b/sys/fs/msdosfs/msdosfs_fat.c --- a/sys/fs/msdosfs/msdosfs_fat.c +++ b/sys/fs/msdosfs/msdosfs_fat.c @@ -204,7 +204,8 @@ if (bn != bp_bn) { if (bp) brelse(bp); - error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp); + error = breadb(pmp->pm_devvp, bntolbn(pmp, bn), bn, bsize, + NOCRED, &bp); if (error) { return (error); } @@ -339,8 +340,8 @@ for (i = 1; i < pmp->pm_FATs; i++) { fatbn += pmp->pm_FATsecs; /* getblk() never fails */ - bpn = getblk(pmp->pm_devvp, fatbn, bp->b_bcount, - 0, 0, 0); + bpn = getblkb(pmp->pm_devvp, bntolbn(pmp, fatbn), fatbn, + bp->b_bcount, 0, 0, 0); memcpy(bpn->b_data, bp->b_data, bp->b_bcount); /* Force the clean bit on in the other copies. */ if (cleanfat == 16) @@ -509,7 +510,8 @@ byteoffset = FATOFS(pmp, cn); fatblock(pmp, byteoffset, &bn, &bsize, &bo); - error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp); + error = breadb(pmp->pm_devvp, bntolbn(pmp, bn), bn, bsize, + NOCRED, &bp); if (error) { return (error); } @@ -591,7 +593,8 @@ while (count > 0) { byteoffset = FATOFS(pmp, start); fatblock(pmp, byteoffset, &bn, &bsize, &bo); - error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp); + error = breadb(pmp->pm_devvp, bntolbn(pmp, bn), bn, bsize, + NOCRED, &bp); if (error) { return (error); } @@ -845,7 +848,8 @@ if (lbn != bn) { if (bp) updatefats(pmp, bp, lbn); - error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp); + error = breadb(pmp->pm_devvp, bntolbn(pmp, bn), bn, bsize, + NOCRED, &bp); if (error) { MSDOSFS_UNLOCK_MP(pmp); return (error); @@ -927,7 +931,8 @@ if (bp != NULL) brelse(bp); fatblock(pmp, byteoffset, &bn, &bsize, NULL); - error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp); + error = breadb(pmp->pm_devvp, bntolbn(pmp, bn), bn, bsize, + NOCRED, &bp); if (error != 0) return (error); } @@ -946,8 +951,10 @@ if (cn == 0 && readcn != ((pmp->pm_fatmask & 0xffffff00) | pmp->pm_bpb.bpbMedia)) { #ifdef MSDOSFS_DEBUG - printf("mountmsdosfs(): Media descriptor in BPB" - "does not match FAT ID\n"); + printf("mountmsdosfs(): Media descriptor in BPB (%#x) " + "does not match FAT ID (%#lx)\n", + (pmp->pm_fatmask & 0xffffff00) | pmp->pm_bpb.bpbMedia, + readcn); #endif brelse(bp); return (EINVAL); @@ -1076,19 +1083,21 @@ /* * Get the buf header for the new block of the file. */ - if (dep->de_Attributes & ATTR_DIRECTORY) - bp = getblk(pmp->pm_devvp, - cntobn(pmp, cn++), + if (dep->de_Attributes & ATTR_DIRECTORY) { + blkno = cntobn(pmp, cn++); + bp = getblkb(pmp->pm_devvp, + bntolbn(pmp, blkno), blkno, pmp->pm_bpcluster, 0, 0, 0); - else { - bp = getblk(DETOV(dep), - frcn++, + } else { + blkno = frcn++; + bp = getblkb(DETOV(dep), + bntolbn(pmp, blkno), blkno, pmp->pm_bpcluster, 0, 0, 0); /* * Do the bmap now, as in msdosfs_write */ if (pcbmap(dep, - bp->b_lblkno, + bp->b_blkno, &blkno, 0, 0)) bp->b_blkno = -1; if (bp->b_blkno == -1) @@ -1160,7 +1169,8 @@ */ byteoffset = FATOFS(pmp, 1); fatblock(pmp, byteoffset, &bn, &bsize, &bo); - error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp); + error = breadb(pmp->pm_devvp, bntolbn(pmp, bn), bn, bsize, + NOCRED, &bp); if (error) return (error); diff --git a/sys/fs/msdosfs/msdosfs_lookup.c b/sys/fs/msdosfs/msdosfs_lookup.c --- a/sys/fs/msdosfs/msdosfs_lookup.c +++ b/sys/fs/msdosfs/msdosfs_lookup.c @@ -253,7 +253,8 @@ break; return (error); } - error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp); + error = breadb(pmp->pm_devvp, bntolbn(pmp, bn), bn, blsize, + NOCRED, &bp); if (error) { return (error); } @@ -678,7 +679,8 @@ diroffset = ddep->de_fndoffset; if (dirclust != MSDOSFSROOT) diroffset &= pmp->pm_crbomask; - if ((error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) != 0) { + if ((error = breadb(pmp->pm_devvp, bntolbn(pmp, bn), bn, blsize, + NOCRED, &bp)) != 0) { brelse(bp); return error; } @@ -711,8 +713,8 @@ if (error) return error; - error = bread(pmp->pm_devvp, bn, blsize, - NOCRED, &bp); + error = breadb(pmp->pm_devvp, bntolbn(pmp, bn), + bn, blsize, NOCRED, &bp); if (error) { return error; } @@ -778,7 +780,8 @@ return (1); /* it's empty */ return (0); } - error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp); + error = breadb(pmp->pm_devvp, bntolbn(pmp, bn), bn, blsize, + NOCRED, &bp); if (error) { return (0); } @@ -834,6 +837,7 @@ doscheckpath(struct denode *source, struct denode *target, daddr_t *wait_scn) { daddr_t scn; + daddr_t bn; struct msdosfsmount *pmp; struct direntry *ep; struct denode *dep; @@ -866,7 +870,8 @@ break; } scn = dep->de_StartCluster; - error = bread(pmp->pm_devvp, cntobn(pmp, scn), + bn = cntobn(pmp, scn); + error = breadb(pmp->pm_devvp, bntolbn(pmp, bn), bn, pmp->pm_bpcluster, NOCRED, &bp); if (error != 0) break; @@ -934,7 +939,8 @@ && de_blk(pmp, diroffset + blsize) > pmp->pm_rootdirsize) blsize = de_bn2off(pmp, pmp->pm_rootdirsize) & pmp->pm_crbomask; bn = detobn(pmp, dirclust, diroffset); - if ((error = bread(pmp->pm_devvp, bn, blsize, NOCRED, bpp)) != 0) { + if ((error = breadb(pmp->pm_devvp, bntolbn(pmp, bn), bn, blsize, + NOCRED, bpp)) != 0) { brelse(*bpp); *bpp = NULL; return (error); @@ -991,7 +997,8 @@ error = pcbmap(pdep, de_cluster(pmp, offset), &bn, 0, &blsize); if (error) return error; - error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp); + error = breadb(pmp->pm_devvp, bntolbn(pmp, bn), bn, blsize, + NOCRED, &bp); if (error) { return error; } @@ -1068,7 +1075,8 @@ return 0; return error; } - error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp); + error = breadb(pmp->pm_devvp, bntolbn(pmp, bn), bn, blsize, + NOCRED, &bp); if (error) { return error; } diff --git a/sys/fs/msdosfs/msdosfs_vfsops.c b/sys/fs/msdosfs/msdosfs_vfsops.c --- a/sys/fs/msdosfs/msdosfs_vfsops.c +++ b/sys/fs/msdosfs/msdosfs_vfsops.c @@ -457,7 +457,8 @@ printf("rootdir_free: dirclu=%d dirleft=%d readsize=%lu\n", dirclu, dirleft, readsize); #endif - if (bread(pmp->pm_devvp, dirclu, readsize, NOCRED, &bp) != 0) { + if (breadb(pmp->pm_devvp, bntolbn(pmp, dirclu), dirclu, readsize, + NOCRED, &bp) != 0) { printf("rootdir_free: read error\n"); if (bp != NULL) brelse(bp); @@ -757,12 +758,27 @@ goto error_exit; } + /* + * Prevent re-use of the buffer since it has been fetched without offset. + */ + bp->b_flags |= B_NOCACHE|B_NOREUSE; + /* * Release the bootsector buffer. */ brelse(bp); bp = NULL; + /* + * Calculate sector offset required to align clusters with page boundaries. + */ + pmp->pm_cacheblockoffs = -pmp->pm_firstcluster % de_off2bn(pmp, PAGE_SIZE); +//#ifdef MSDOSFS_DEBUG + printf("mountmsdosfs(): firstcluster=%lu bpcluster=%lu bnshift=%lu cacheblockoffs=%lu\n", + pmp->pm_firstcluster, pmp->pm_bpcluster, pmp->pm_bnshift, pmp->pm_cacheblockoffs); +//#endif +// pmp->pm_cacheblockoffs = 0; + /* * Check the fsinfo sector if we have one. Silently fix up our * in-core copy of fp->fsinxtfree if it is unknown (0xffffffff) @@ -771,8 +787,10 @@ */ if (pmp->pm_fsinfo) { struct fsinfo *fp; + daddr_t bn; - if ((error = bread(devvp, pmp->pm_fsinfo, pmp->pm_BytesPerSec, + bn = pmp->pm_fsinfo; + if ((error = breadb(devvp, bntolbn(pmp, bn), bn, pmp->pm_BytesPerSec, NOCRED, &bp)) != 0) goto error_exit; fp = (struct fsinfo *)bp->b_data; @@ -1073,6 +1091,7 @@ { struct fsinfo *fp; struct buf *bp; + daddr_t bn; int error; MSDOSFS_LOCK_MP(pmp); @@ -1080,7 +1099,8 @@ error = 0; goto unlock; } - error = bread(pmp->pm_devvp, pmp->pm_fsinfo, pmp->pm_BytesPerSec, + bn = pmp->pm_fsinfo; + error = breadb(pmp->pm_devvp, bntolbn(pmp, bn), bn, pmp->pm_BytesPerSec, NOCRED, &bp); if (error != 0) { goto unlock; diff --git a/sys/fs/msdosfs/msdosfs_vnops.c b/sys/fs/msdosfs/msdosfs_vnops.c --- a/sys/fs/msdosfs/msdosfs_vnops.c +++ b/sys/fs/msdosfs/msdosfs_vnops.c @@ -573,18 +573,20 @@ break; } else if (error) break; - error = bread(pmp->pm_devvp, lbn, blsize, NOCRED, &bp); + error = breadb(pmp->pm_devvp, bntolbn(pmp, lbn), lbn, blsize, + NOCRED, &bp); } else if (de_cn2off(pmp, rablock) >= dep->de_FileSize) { - error = bread(vp, lbn, blsize, NOCRED, &bp); - } else if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) { + error = breadb(vp, bntolbn(pmp, lbn), lbn, blsize, NOCRED, &bp); + } else if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0 && + pmp->pm_cacheblockoffs == 0) { error = cluster_read(vp, dep->de_FileSize, lbn, blsize, NOCRED, on + uio->uio_resid, seqcount, 0, &bp); } else if (seqcount > 1) { rasize = blsize; - error = breadn(vp, lbn, + error = breadbn(vp, bntolbn(pmp, lbn), lbn, blsize, &rablock, &rasize, 1, NOCRED, &bp); } else { - error = bread(vp, lbn, blsize, NOCRED, &bp); + error = breadb(vp, bntolbn(pmp, lbn), lbn, blsize, NOCRED, &bp); } if (error) { brelse(bp); @@ -729,7 +731,8 @@ * or we write the cluster from its start beyond EOF, * then no need to read data from disk. */ - bp = getblk(thisvp, bn, pmp->pm_bpcluster, 0, 0, 0); + bp = getblkb(thisvp, bntolbn(pmp, bn), bn, pmp->pm_bpcluster, + 0, 0, 0); /* * This call to vfs_bio_clrbuf() ensures that * even if vn_io_fault_uiomove() below faults, @@ -741,8 +744,8 @@ * Do the bmap now, since pcbmap needs buffers * for the FAT table. (see msdosfs_strategy) */ - if (bp->b_blkno == bp->b_lblkno) { - error = pcbmap(dep, bp->b_lblkno, &bn, 0, 0); + if (bntolbn(pmp, bp->b_blkno) == bp->b_lblkno) { // XXX ??? + error = pcbmap(dep, bp->b_blkno, &bn, 0, 0); if (error) bp->b_blkno = -1; else @@ -758,7 +761,8 @@ /* * The block we need to write into exists, so read it in. */ - error = bread(thisvp, bn, pmp->pm_bpcluster, cred, &bp); + error = breadb(thisvp, bntolbn(pmp, bn), bn, pmp->pm_bpcluster, + cred, &bp); if (error) { break; } @@ -797,7 +801,8 @@ else if (vm_page_count_severe() || buf_dirty_count_severe()) bawrite(bp); else if (n + croffset == pmp->pm_bpcluster) { - if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERW) == 0) + if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERW) == 0 && + pmp->pm_cacheblockoffs == 0) cluster_write(vp, &dep->de_clusterw, bp, dep->de_FileSize, seqcount, 0); else @@ -1237,10 +1242,10 @@ if (cn == MSDOSFSROOT) { /* this should never happen */ panic("msdosfs_rename(): updating .. in root directory?"); - } else - bn = cntobn(pmp, cn); - error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, - NOCRED, &bp); + } + bn = cntobn(pmp, cn); + error = breadb(pmp->pm_devvp, bntolbn(pmp, bn), bn, + pmp->pm_bpcluster, NOCRED, &bp); if (error != 0) { printf("%s: block read error %d while renaming dir\n", pmp->pm_mountp->mnt_stat.f_mntonname, @@ -1380,7 +1385,8 @@ */ bn = cntobn(pmp, newcluster); /* always succeeds */ - bp = getblk(pmp->pm_devvp, bn, pmp->pm_bpcluster, 0, 0, 0); + bp = getblkb(pmp->pm_devvp, bntolbn(pmp, bn), bn, pmp->pm_bpcluster, + 0, 0, 0); memset(bp->b_data, 0, pmp->pm_bpcluster); memcpy(bp->b_data, &dosdirtemplate, sizeof dosdirtemplate); denp = (struct direntry *)bp->b_data; @@ -1629,7 +1635,8 @@ error = pcbmap(dep, lbn, &bn, &cn, &blsize); if (error) break; - error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp); + error = breadb(pmp->pm_devvp, bntolbn(pmp, bn), bn, blsize, + NOCRED, &bp); if (error) { return (error); } diff --git a/sys/fs/msdosfs/msdosfsmount.h b/sys/fs/msdosfs/msdosfsmount.h --- a/sys/fs/msdosfs/msdosfsmount.h +++ b/sys/fs/msdosfs/msdosfsmount.h @@ -91,6 +91,7 @@ u_long pm_rootdirblk; /* block # (cluster # for FAT32) of root directory number */ u_long pm_rootdirsize; /* size in blocks (not clusters) */ u_long pm_firstcluster; /* block number of first cluster */ + u_long pm_cacheblockoffs; /* offset from physical block to buffer cache block number */ u_long pm_maxcluster; /* maximum cluster number */ u_long pm_freeclustercount; /* number of free clusters */ u_long pm_cnshift; /* shift file offset right this amount to get a cluster number */ @@ -201,6 +202,13 @@ */ #define de_bn2off(pmp, bn) \ ((bn) << (pmp)->pm_bnshift) + +/* + * Convert offset to block number + */ +#define de_off2bn(pmp, off) \ + ((off) >> (pmp)->pm_bnshift) + /* * Map a cluster number into a filesystem relative block number. */ @@ -213,6 +221,12 @@ #define roottobn(pmp, dirofs) \ (de_blk((pmp), (dirofs)) + (pmp)->pm_rootdirblk) +/* + * Calculate buffer cache block number from disk block number + */ +#define bntolbn(pmp, bn) \ + ((pmp)->pm_cacheblockoffs + (bn)) + /* * Calculate block number for directory entry at cluster dirclu, offset * dirofs diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c --- a/sys/kern/vfs_bio.c +++ b/sys/kern/vfs_bio.c @@ -3289,7 +3289,7 @@ */ if (ncl != 1) { BUF_UNLOCK(bp); - nwritten = cluster_wbuild(vp, size, lblkno - j, ncl, + nwritten = cluster_wbuild(vp, size, lblkno - j, ncl, // XXX only lblkno used !!! gbflags); return (nwritten); } @@ -3914,17 +3914,24 @@ } } +struct buf * +getblkb(struct vnode *vp, daddr_t blkno, daddr_t dblkno, int size, int slpflag, + int slptimeo, int flags) +{ + struct buf *bp; + int error; + + error = getblkx(vp, blkno, dblkno, size, slpflag, slptimeo, flags, &bp); + if (error != 0) + return (NULL); + return (bp); +} + struct buf * getblk(struct vnode *vp, daddr_t blkno, int size, int slpflag, int slptimeo, int flags) { - struct buf *bp; - int error; - - error = getblkx(vp, blkno, blkno, size, slpflag, slptimeo, flags, &bp); - if (error != 0) - return (NULL); - return (bp); + return (getblkb(vp, blkno, blkno, size, slpflag, slptimeo, flags)); } /* diff --git a/sys/sys/buf.h b/sys/sys/buf.h --- a/sys/sys/buf.h +++ b/sys/sys/buf.h @@ -549,12 +549,18 @@ #define bread(vp, blkno, size, cred, bpp) \ breadn_flags(vp, blkno, blkno, size, NULL, NULL, 0, cred, 0, \ NULL, bpp) +#define breadb(vp, blkno, dblkno, size, cred, bpp) \ + breadn_flags(vp, blkno, dblkno, size, NULL, NULL, 0, cred, 0, \ + NULL, bpp) #define bread_gb(vp, blkno, size, cred, gbflags, bpp) \ 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, blkno, size, rablkno, rabsize, cnt, cred, \ 0, NULL, bpp) +#define breadbn(vp, blkno, dblkno, size, rablkno, rabsize, cnt, cred, bpp) \ + breadn_flags(vp, blkno, dblkno, size, rablkno, rabsize, cnt, cred, \ + 0, NULL, bpp) 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 *); @@ -574,6 +580,7 @@ struct buf *gbincore(struct bufobj *, daddr_t); struct buf *gbincore_unlocked(struct bufobj *, daddr_t); struct buf *getblk(struct vnode *, daddr_t, int, int, int, int); +struct buf *getblkb(struct vnode *, daddr_t, daddr_t, int, int, int, int); 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);