This is the 4th attempt to implement clustering for msdosfs.  See [0]
for the previous story.

This version implements the strict necessary to read a maximum of 64k
per read.  Unlike the previous version we no longer mix cluster and
block numbers.

This speeds up msdosfs reads significantly.  Regress tests are passing.

I'd appreciate more tests and reviews.

[0] https://marc.info/?l=openbsd-tech&m=150281045927010&w=2


Index: msdosfs/denode.h
===================================================================
RCS file: /cvs/src/sys/msdosfs/denode.h,v
retrieving revision 1.32
diff -u -p -r1.32 denode.h
--- msdosfs/denode.h    13 Jun 2017 18:13:18 -0000      1.32
+++ msdosfs/denode.h    26 Apr 2018 19:32:57 -0000
@@ -142,7 +142,6 @@ struct denode {
        struct vnode *de_devvp; /* vnode of blk dev we live on */
        uint32_t de_flag;               /* flag bits */
        dev_t de_dev;           /* device where direntry lives */
-       daddr_t de_lastr;
        uint32_t de_dirclust;   /* cluster of the directory file containing 
this entry */
        uint32_t de_diroffset;  /* offset of this entry in the directory 
cluster */
        uint32_t de_fndoffset;  /* offset of found dir entry */
Index: msdosfs/msdosfs_vnops.c
===================================================================
RCS file: /cvs/src/sys/msdosfs/msdosfs_vnops.c,v
retrieving revision 1.117
diff -u -p -r1.117 msdosfs_vnops.c
--- msdosfs/msdosfs_vnops.c     2 Jan 2018 06:38:45 -0000       1.117
+++ msdosfs/msdosfs_vnops.c     26 Apr 2018 19:32:57 -0000
@@ -78,13 +78,13 @@
 
 static uint32_t fileidhash(uint64_t);
 
+int msdosfs_bmaparray(struct vnode *, daddr_t, daddr_t *, int *);
 int msdosfs_kqfilter(void *);
 int filt_msdosfsread(struct knote *, long);
 int filt_msdosfswrite(struct knote *, long);
 int filt_msdosfsvnode(struct knote *, long);
 void filt_msdosfsdetach(struct knote *);
 
-
 /*
  * Some general notes:
  *
@@ -510,18 +510,14 @@ int
 msdosfs_read(void *v)
 {
        struct vop_read_args *ap = v;
-       int error = 0;
-       uint32_t diff;
-       int blsize;
-       int isadir;
-       uint32_t n;
-       long on;
-       daddr_t lbn, rablock, rablkno;
-       struct buf *bp;
        struct vnode *vp = ap->a_vp;
        struct denode *dep = VTODE(vp);
        struct msdosfsmount *pmp = dep->de_pmp;
        struct uio *uio = ap->a_uio;
+       int isadir, error = 0;
+       uint32_t n, diff, size, on;
+       struct buf *bp;
+       daddr_t cn, bn;
 
        /*
         * If they didn't ask for any data, then we are done.
@@ -536,7 +532,8 @@ msdosfs_read(void *v)
                if (uio->uio_offset >= dep->de_FileSize)
                        return (0);
 
-               lbn = de_cluster(pmp, uio->uio_offset);
+               cn = de_cluster(pmp, uio->uio_offset);
+               size = pmp->pm_bpcluster;
                on = uio->uio_offset & pmp->pm_crbomask;
                n = ulmin(pmp->pm_bpcluster - on, uio->uio_resid);
 
@@ -549,31 +546,24 @@ msdosfs_read(void *v)
                if (diff < n)
                        n = diff;
 
-               /* convert cluster # to block # if a directory */
-               if (isadir) {
-                       error = pcbmap(dep, lbn, &lbn, 0, &blsize);
-                       if (error)
-                               return (error);
-               }
                /*
                 * If we are operating on a directory file then be sure to
                 * do i/o with the vnode for the filesystem instead of the
-                * vnode for the directory.
+                * vnode for the directory. In that case, the block number
+                * is physical blocks and not clusters.
                 */
                if (isadir) {
-                       error = bread(pmp->pm_devvp, lbn, blsize, &bp);
+                       /* dirfile-relative cn -> fs-relative bn */
+                       error = pcbmap(dep, cn, &bn, 0, &size);
+                       if (error)
+                               return (error);
+                       error = bread(pmp->pm_devvp, bn, size, &bp);
                } else {
-                       rablock = lbn + 1;
-                       rablkno = de_cn2bn(pmp, rablock);
-                       if (dep->de_lastr + 1 == lbn &&
-                           de_cn2off(pmp, rablock) < dep->de_FileSize)
-                               error = breadn(vp, de_cn2bn(pmp, lbn),
-                                   pmp->pm_bpcluster, &rablkno,
-                                   &pmp->pm_bpcluster, 1, &bp);
+                       bn = de_cn2bn(pmp, cn);
+                       if (de_cn2off(pmp, cn + 1) >= dep->de_FileSize)
+                               error = bread(vp, bn, size, &bp);
                        else
-                               error = bread(vp, de_cn2bn(pmp, lbn),
-                                   pmp->pm_bpcluster, &bp);
-                       dep->de_lastr = lbn;
+                               error = bread_cluster(vp, bn, size, &bp);
                }
                n = min(n, pmp->pm_bpcluster - bp->b_resid);
                if (error) {
@@ -1756,7 +1746,7 @@ msdosfs_islocked(void *v)
 
 /*
  * vp  - address of vnode file the file
- * bn  - which cluster we are interested in mapping to a filesystem block 
number.
+ * bn  - which cluster we are interested in mapping to a filesystem block 
number
  * vpp - returns the vnode for the block special file holding the filesystem
  *      containing the file of interest
  * bnp - address of where to return the filesystem relative block number
@@ -1766,19 +1756,52 @@ msdosfs_bmap(void *v)
 {
        struct vop_bmap_args *ap = v;
        struct denode *dep = VTODE(ap->a_vp);
-       struct msdosfsmount *pmp = dep->de_pmp;
 
        if (ap->a_vpp != NULL)
                *ap->a_vpp = dep->de_devvp;
        if (ap->a_bnp == NULL)
                return (0);
-       if (ap->a_runp) {
+
+       return (msdosfs_bmaparray(ap->a_vp, ap->a_bn, ap->a_bnp, ap->a_runp));
+}
+
+int
+msdosfs_bmaparray(struct vnode *vp, daddr_t bn, daddr_t *bnp, int *runp)
+{
+       struct denode *dep = VTODE(vp);
+       struct msdosfsmount *pmp = dep->de_pmp;
+       struct mount *mp;
+       int error, maxrun = 0, run;
+       daddr_t daddr;
+       daddr_t cn = de_bn2cn(pmp, bn);
+
+       mp = vp->v_mount;
+
+       if (runp) {
                /*
-                * Sequential clusters should be counted here.
+                * XXX
+                * If MAXBSIZE is the largest transfer the disks can handle,
+                * we probably want maxrun to be 1 block less so that we
+                * don't create a block larger than the device can handle.
                 */
-               *ap->a_runp = 0;
+               *runp = 0;
+               maxrun = min(MAXBSIZE / mp->mnt_stat.f_iosize - 1,
+                   pmp->pm_maxcluster - cn);
        }
-       return (pcbmap(dep, de_bn2cn(pmp, ap->a_bn), ap->a_bnp, 0, 0));
+
+       if ((error = pcbmap(dep, cn, bnp, 0, 0)) != 0)
+               return (error);
+
+       for (run = 1; run <= maxrun; run++) {
+               error = pcbmap(dep, cn + run, &daddr, 0, 0);
+               if (error != 0 || (daddr != *bnp + de_cn2bn(pmp, run)))
+                       break;
+       }
+
+       if (runp)
+               *runp = run - 1;
+
+       return (0);
 }
 
 int

Reply via email to