Martin Pieuchot wrote:
> On 03/01/16(Sun) 23:10, Martin Pieuchot wrote:
> > Reading files on msdos-formated USB sticks under OpenBSD is really slow.
> > *One* of the reasons is that only one block is currently read-ahead if
> > possible.
> > 
> > Diff below converts msdosfs_read() to use bread_cluster() which at least
> > double the transfer rate when reading sequential blocks here.
> > 
> > When combined with the previous bread_cluster() diff, I get almost the
> > same read performances as with the raw device.
> > 
> > With a cheap USB device here, I have:
> > 
> >   Kernel:                   Max measure read speed:
> > 
> >   -current                           3.2M
> >   -current+this diff                         6.8M
> >   -current+this diff+bread_cluster  11.8M
> >   physio(9)                         12.4M
> 
> I forgot to mention that these tests were performed with a 64k blocks.
> 
> Here's an updated diff that gets rid of the now unused 'de_lastr'
> argument.  It makes use of 'mp->mnt_stat.f_iosize' to reduce differences
> with UFS and the old cluster code.  Finally it renames some variables
> from 'lbn' to 'cn' to better reflect what we're dealing with.

Hi,

I've been testing the two diff lately (this one + bread_cluster), i've
seen no regression and I can confirm that it speeds up the reading here
too (by a smaller factor though, but it's with shitty hardware).


> 
> Index: msdosfs/denode.h
> ===================================================================
> RCS file: /cvs/src/sys/msdosfs/denode.h,v
> retrieving revision 1.27
> diff -u -p -r1.27 denode.h
> --- msdosfs/denode.h  23 Oct 2015 10:45:31 -0000      1.27
> +++ msdosfs/denode.h  7 Jan 2016 16:36:08 -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.104
> diff -u -p -r1.104 msdosfs_vnops.c
> --- msdosfs/msdosfs_vnops.c   23 Oct 2015 18:04:37 -0000      1.104
> +++ msdosfs/msdosfs_vnops.c   7 Jan 2016 16:36:55 -0000
> @@ -77,13 +77,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:
>   *
> @@ -511,18 +511,15 @@ 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;
> +     struct buf *bp;
> +     daddr_t cn;
> +     long on;
>  
>       /*
>        * If they didn't ask for any data, then we are done.
> @@ -537,7 +534,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 = min((uint32_t) (pmp->pm_bpcluster - on), uio->uio_resid);
>  
> @@ -550,31 +548,21 @@ 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.
>                */
>               if (isadir) {
> -                     error = bread(pmp->pm_devvp, lbn, blsize, &bp);
> +                     error = pcbmap(dep, cn, &cn, 0, &size);
> +                     if (error)
> +                             return (error);
> +                     error = bread(pmp->pm_devvp, cn, 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);
> +                     if (de_cn2off(pmp, cn + 1) >= dep->de_FileSize)
> +                             error = bread(vp, cn, size, &bp);
>                       else
> -                             error = bread(vp, de_cn2bn(pmp, lbn),
> -                                 pmp->pm_bpcluster, &bp);
> -                     dep->de_lastr = lbn;
> +                             error = bread_cluster(vp, cn, size, &bp);
>               }
>               n = min(n, pmp->pm_bpcluster - bp->b_resid);
>               if (error) {
> @@ -604,7 +592,7 @@ msdosfs_write(void *v)
>       uint32_t osize;
>       int error = 0;
>       uint32_t count, lastcn;
> -     daddr_t bn;
> +     daddr_t cn;
>       struct buf *bp;
>       int ioflag = ap->a_ioflag;
>       struct uio *uio = ap->a_uio;
> @@ -680,32 +668,34 @@ msdosfs_write(void *v)
>               lastcn = de_clcount(pmp, osize) - 1;
>  
>       do {
> -             if (de_cluster(pmp, uio->uio_offset) > lastcn) {
> +             croffset = uio->uio_offset & pmp->pm_crbomask;
> +             cn = de_cluster(pmp, uio->uio_offset);
> +
> +             if (cn > lastcn) {
>                       error = ENOSPC;
>                       break;
>               }
>  
> -             bn = de_blk(pmp, uio->uio_offset);
> -             if ((uio->uio_offset & pmp->pm_crbomask) == 0
> -                 && (de_blk(pmp, uio->uio_offset + uio->uio_resid) > 
> de_blk(pmp, uio->uio_offset)
> -                     || uio->uio_offset + uio->uio_resid >= 
> dep->de_FileSize)) {
> +             if (croffset == 0 &&
> +                 (de_cluster(pmp, uio->uio_offset + uio->uio_resid) > cn ||
> +                  (uio->uio_offset + uio->uio_resid) >= dep->de_FileSize)) {
>                       /*
>                        * If either the whole cluster gets written,
>                        * 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);
> +                     bp = getblk(thisvp, cn, pmp->pm_bpcluster, 0, 0);
>                       clrbuf(bp);
>                       /*
>                        * 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,
> -                                            de_bn2cn(pmp, bp->b_lblkno),
> -                                            &bp->b_blkno, 0, 0);
> +                             error = pcbmap(dep, bp->b_lblkno, &cn, 0, 0);
>                               if (error)
>                                       bp->b_blkno = -1;
> +                             else
> +                                     bp->b_blkno = cn;
>                       }
>                       if (bp->b_blkno == -1) {
>                               brelse(bp);
> @@ -715,16 +705,16 @@ msdosfs_write(void *v)
>                       }
>               } else {
>                       /*
> -                      * The block we need to write into exists, so read it 
> in.
> +                      * The block we need to write into exists, so
> +                      * read it in.
>                        */
> -                     error = bread(thisvp, bn, pmp->pm_bpcluster, &bp);
> +                     error = bread(thisvp, cn, pmp->pm_bpcluster, &bp);
>                       if (error) {
>                               brelse(bp);
>                               break;
>                       }
>               }
>  
> -             croffset = uio->uio_offset & pmp->pm_crbomask;
>               n = min(uio->uio_resid, pmp->pm_bpcluster - croffset);
>               if (uio->uio_offset + n > dep->de_FileSize) {
>                       dep->de_FileSize = uio->uio_offset + n;
> @@ -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,51 @@ 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 cn, 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;
> +
> +     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
> @@ -1800,8 +1822,7 @@ msdosfs_strategy(void *v)
>        * don't allow files with holes, so we shouldn't ever see this.
>        */
>       if (bp->b_blkno == bp->b_lblkno) {
> -             error = pcbmap(dep, de_bn2cn(dep->de_pmp, bp->b_lblkno),
> -                            &bp->b_blkno, 0, 0);
> +             error = pcbmap(dep, bp->b_lblkno, &bp->b_blkno, 0, 0);
>               if (error)
>                       bp->b_blkno = -1;
>               if (bp->b_blkno == -1)
> 

Reply via email to