The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/md.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: md.c,v 1.87 2023/01/13 15:46:40 hannken Exp $  */
    2 
    3 /*
    4  * Copyright (c) 1995 Gordon W. Ross, Leo Weppelman.
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   26  */
   27 
   28 /*
   29  * This implements a general-purpose memory-disk.
   30  * See md.h for notes on the config types.
   31  *
   32  * Note that this driver provides the same functionality
   33  * as the MFS filesystem hack, but this is better because
   34  * you can use this for any filesystem type you'd like!
   35  *
   36  * Credit for most of the kmem ramdisk code goes to:
   37  *   Leo Weppelman (atari) and Phil Nelson (pc532)
   38  * Credit for the ideas behind the "user space memory" code goes
   39  * to the authors of the MFS implementation.
   40  */
   41 
   42 #include <sys/cdefs.h>
   43 __KERNEL_RCSID(0, "$NetBSD: md.c,v 1.87 2023/01/13 15:46:40 hannken Exp $");
   44 
   45 #ifdef _KERNEL_OPT
   46 #include "opt_md.h"
   47 #else
   48 #define MEMORY_DISK_SERVER 1
   49 #endif
   50 
   51 #include <sys/param.h>
   52 #include <sys/kernel.h>
   53 #include <sys/kmem.h>
   54 #include <sys/systm.h>
   55 #include <sys/buf.h>
   56 #include <sys/bufq.h>
   57 #include <sys/device.h>
   58 #include <sys/disk.h>
   59 #include <sys/stat.h>
   60 #include <sys/proc.h>
   61 #include <sys/conf.h>
   62 #include <sys/disklabel.h>
   63 
   64 #include <uvm/uvm_extern.h>
   65 
   66 #include <dev/md.h>
   67 
   68 #include "ioconf.h"
   69 /*
   70  * The user-space functionality is included by default.
   71  * Use  `options MEMORY_DISK_SERVER=0' to turn it off.
   72  */
   73 #ifndef MEMORY_DISK_SERVER
   74 #error MEMORY_DISK_SERVER should be defined by opt_md.h
   75 #endif  /* MEMORY_DISK_SERVER */
   76 
   77 /*
   78  * We should use the raw partition for ioctl.
   79  */
   80 #define MD_UNIT(unit)   DISKUNIT(unit)
   81 
   82 /* autoconfig stuff... */
   83 
   84 struct md_softc {
   85         device_t sc_dev;        /* Self. */
   86         struct disk sc_dkdev;   /* hook for generic disk handling */
   87         struct md_conf sc_md;
   88         kmutex_t sc_lock;       /* Protect self. */
   89         kcondvar_t sc_cv;       /* Wait here for work. */
   90         struct bufq_state *sc_buflist;
   91 };
   92 /* shorthand for fields in sc_md: */
   93 #define sc_addr sc_md.md_addr
   94 #define sc_size sc_md.md_size
   95 #define sc_type sc_md.md_type
   96 
   97 static void     md_attach(device_t, device_t, void *);
   98 static int      md_detach(device_t, int);
   99 
  100 static dev_type_open(mdopen);
  101 static dev_type_close(mdclose);
  102 static dev_type_read(mdread);
  103 static dev_type_write(mdwrite);
  104 static dev_type_ioctl(mdioctl);
  105 static dev_type_strategy(mdstrategy);
  106 static dev_type_size(mdsize);
  107 
  108 const struct bdevsw md_bdevsw = {
  109         .d_open = mdopen,
  110         .d_close = mdclose,
  111         .d_strategy = mdstrategy,
  112         .d_ioctl = mdioctl,
  113         .d_dump = nodump,
  114         .d_psize = mdsize,
  115         .d_discard = nodiscard,
  116         .d_flag = D_DISK | D_MPSAFE
  117 };
  118 
  119 const struct cdevsw md_cdevsw = {
  120         .d_open = mdopen,
  121         .d_close = mdclose,
  122         .d_read = mdread,
  123         .d_write = mdwrite,
  124         .d_ioctl = mdioctl,
  125         .d_stop = nostop,
  126         .d_tty = notty,
  127         .d_poll = nopoll,
  128         .d_mmap = nommap,
  129         .d_kqfilter = nokqfilter,
  130         .d_discard = nodiscard,
  131         .d_flag = D_DISK | D_MPSAFE
  132 };
  133 
  134 static const struct dkdriver mddkdriver = {
  135         .d_strategy = mdstrategy,
  136         .d_minphys = minphys
  137 };
  138 
  139 CFATTACH_DECL3_NEW(md, sizeof(struct md_softc),
  140         0, md_attach, md_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN);
  141 
  142 static kmutex_t md_device_lock;         /* Protect unit creation / deletion. */
  143 extern size_t md_root_size;
  144 
  145 static void md_set_disklabel(struct md_softc *);
  146 
  147 /*
  148  * This is called if we are configured as a pseudo-device
  149  */
  150 void
  151 mdattach(int n)
  152 {
  153 
  154         mutex_init(&md_device_lock, MUTEX_DEFAULT, IPL_NONE);
  155         if (config_cfattach_attach(md_cd.cd_name, &md_ca)) {
  156                 aprint_error("%s: cfattach_attach failed\n", md_cd.cd_name);
  157                 return;
  158         }
  159 }
  160 
  161 static void
  162 md_attach(device_t parent, device_t self, void *aux)
  163 {
  164         struct md_softc *sc = device_private(self);
  165 
  166         sc->sc_dev = self;
  167         sc->sc_type = MD_UNCONFIGURED;
  168         mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
  169         cv_init(&sc->sc_cv, "mdidle");
  170         bufq_alloc(&sc->sc_buflist, "fcfs", 0);
  171 
  172         /* XXX - Could accept aux info here to set the config. */
  173 #ifdef  MEMORY_DISK_HOOKS
  174         /*
  175          * This external function might setup a pre-loaded disk.
  176          * All it would need to do is setup the md_conf struct.
  177          * See sys/dev/md_root.c for an example.
  178          */
  179         md_attach_hook(device_unit(self), &sc->sc_md);
  180 #endif
  181 
  182         /*
  183          * Initialize and attach the disk structure.
  184          */
  185         disk_init(&sc->sc_dkdev, device_xname(self), &mddkdriver);
  186         disk_attach(&sc->sc_dkdev);
  187 
  188         if (sc->sc_type != MD_UNCONFIGURED)
  189                 md_set_disklabel(sc);
  190 
  191         if (!pmf_device_register(self, NULL, NULL))
  192                 aprint_error_dev(self, "couldn't establish power handler\n");
  193 }
  194 
  195 static int
  196 md_detach(device_t self, int flags)
  197 {
  198         struct md_softc *sc = device_private(self);
  199         int rc;
  200 
  201         rc = 0;
  202         mutex_enter(&sc->sc_dkdev.dk_openlock);
  203         if (sc->sc_dkdev.dk_openmask == 0 && sc->sc_type == MD_UNCONFIGURED)
  204                 ;       /* nothing to do */
  205         else if ((flags & DETACH_FORCE) == 0)
  206                 rc = EBUSY;
  207         mutex_exit(&sc->sc_dkdev.dk_openlock);
  208 
  209         if (rc != 0)
  210                 return rc;
  211 
  212         pmf_device_deregister(self);
  213         disk_detach(&sc->sc_dkdev);
  214         disk_destroy(&sc->sc_dkdev);
  215         bufq_free(sc->sc_buflist);
  216         mutex_destroy(&sc->sc_lock);
  217         cv_destroy(&sc->sc_cv);
  218         return 0;
  219 }
  220 
  221 /*
  222  * operational routines:
  223  * open, close, read, write, strategy,
  224  * ioctl, dump, size
  225  */
  226 
  227 #if MEMORY_DISK_SERVER
  228 static int      md_server_loop(struct md_softc *sc);
  229 static int      md_ioctl_server(struct md_softc *sc, struct md_conf *umd,
  230                     struct lwp *l);
  231 #endif  /* MEMORY_DISK_SERVER */
  232 static int      md_ioctl_kalloc(struct md_softc *sc, struct md_conf *umd,
  233                     struct lwp *l);
  234 
  235 static int
  236 mdsize(dev_t dev)
  237 {
  238         struct md_softc *sc;
  239         int res;
  240 
  241         sc = device_lookup_private(&md_cd, MD_UNIT(dev));
  242         if (sc == NULL)
  243                 return 0;
  244 
  245         mutex_enter(&sc->sc_lock);
  246         if (sc->sc_type == MD_UNCONFIGURED)
  247                 res = 0;
  248         else
  249                 res = sc->sc_size >> DEV_BSHIFT;
  250         mutex_exit(&sc->sc_lock);
  251 
  252         return res;
  253 }
  254 
  255 static int
  256 mdopen(dev_t dev, int flag, int fmt, struct lwp *l)
  257 {
  258         int unit;
  259         int part = DISKPART(dev);
  260         int pmask = 1 << part;
  261         cfdata_t cf;
  262         struct md_softc *sc;
  263         struct disk *dk;
  264 #ifdef  MEMORY_DISK_HOOKS
  265         bool configured;
  266 #endif
  267 
  268         mutex_enter(&md_device_lock);
  269         unit = MD_UNIT(dev);
  270         sc = device_lookup_private(&md_cd, unit);
  271         if (sc == NULL) {
  272                 if (part != RAW_PART) {
  273                         mutex_exit(&md_device_lock);
  274                         return ENXIO;
  275                 }
  276                 cf = kmem_zalloc(sizeof(*cf), KM_SLEEP);
  277                 cf->cf_name = md_cd.cd_name;
  278                 cf->cf_atname = md_cd.cd_name;
  279                 cf->cf_unit = unit;
  280                 cf->cf_fstate = FSTATE_STAR;
  281                 sc = device_private(config_attach_pseudo(cf));
  282                 if (sc == NULL) {
  283                         mutex_exit(&md_device_lock);
  284                         return ENOMEM;
  285                 }
  286         }
  287 
  288         dk = &sc->sc_dkdev;
  289 
  290         /*
  291          * The raw partition is used for ioctl to configure.
  292          */
  293         if (part == RAW_PART)
  294                 goto ok;
  295 
  296 #ifdef  MEMORY_DISK_HOOKS
  297         /* Call the open hook to allow loading the device. */
  298         configured = (sc->sc_type != MD_UNCONFIGURED);
  299         md_open_hook(unit, &sc->sc_md);
  300         /* initialize disklabel if the device is configured in open hook */
  301         if (!configured && sc->sc_type != MD_UNCONFIGURED)
  302                 md_set_disklabel(sc);
  303 #endif
  304 
  305         /*
  306          * This is a normal, "slave" device, so
  307          * enforce initialized.
  308          */
  309         if (sc->sc_type == MD_UNCONFIGURED) {
  310                 mutex_exit(&md_device_lock);
  311                 return ENXIO;
  312         }
  313 
  314 ok:
  315         /* XXX duplicates code in dk_open().  Call dk_open(), instead? */
  316         mutex_enter(&dk->dk_openlock);
  317         /* Mark our unit as open. */
  318         switch (fmt) {
  319         case S_IFCHR:
  320                 dk->dk_copenmask |= pmask;
  321                 break;
  322         case S_IFBLK:
  323                 dk->dk_bopenmask |= pmask;
  324                 break;
  325         }
  326 
  327         dk->dk_openmask = dk->dk_copenmask | dk->dk_bopenmask;
  328 
  329         mutex_exit(&dk->dk_openlock);
  330         mutex_exit(&md_device_lock);
  331         return 0;
  332 }
  333 
  334 static int
  335 mdclose(dev_t dev, int flag, int fmt, struct lwp *l)
  336 {
  337         int part = DISKPART(dev);
  338         int pmask = 1 << part;
  339         int error;
  340         cfdata_t cf;
  341         struct md_softc *sc;
  342         struct disk *dk;
  343 
  344         sc = device_lookup_private(&md_cd, MD_UNIT(dev));
  345         if (sc == NULL)
  346                 return ENXIO;
  347 
  348         dk = &sc->sc_dkdev;
  349 
  350         mutex_enter(&dk->dk_openlock);
  351 
  352         switch (fmt) {
  353         case S_IFCHR:
  354                 dk->dk_copenmask &= ~pmask;
  355                 break;
  356         case S_IFBLK:
  357                 dk->dk_bopenmask &= ~pmask;
  358                 break;
  359         }
  360         dk->dk_openmask = dk->dk_copenmask | dk->dk_bopenmask;
  361         if (dk->dk_openmask != 0) {
  362                 mutex_exit(&dk->dk_openlock);
  363                 return 0;
  364         }
  365 
  366         mutex_exit(&dk->dk_openlock);
  367 
  368         mutex_enter(&md_device_lock);
  369         cf = device_cfdata(sc->sc_dev);
  370         error = config_detach(sc->sc_dev, DETACH_QUIET);
  371         if (! error)
  372                 kmem_free(cf, sizeof(*cf));
  373         mutex_exit(&md_device_lock);
  374         return error;
  375 }
  376 
  377 static int
  378 mdread(dev_t dev, struct uio *uio, int flags)
  379 {
  380         struct md_softc *sc;
  381 
  382         sc = device_lookup_private(&md_cd, MD_UNIT(dev));
  383 
  384         if (sc == NULL || sc->sc_type == MD_UNCONFIGURED)
  385                 return ENXIO;
  386 
  387         return (physio(mdstrategy, NULL, dev, B_READ, minphys, uio));
  388 }
  389 
  390 static int
  391 mdwrite(dev_t dev, struct uio *uio, int flags)
  392 {
  393         struct md_softc *sc;
  394 
  395         sc = device_lookup_private(&md_cd, MD_UNIT(dev));
  396 
  397         if (sc == NULL || sc->sc_type == MD_UNCONFIGURED)
  398                 return ENXIO;
  399 
  400         return (physio(mdstrategy, NULL, dev, B_WRITE, minphys, uio));
  401 }
  402 
  403 /*
  404  * Handle I/O requests, either directly, or
  405  * by passing them to the server process.
  406  */
  407 static void
  408 mdstrategy(struct buf *bp)
  409 {
  410         struct md_softc *sc;
  411         void *  addr;
  412         size_t off, xfer;
  413         bool is_read;
  414 
  415         sc = device_lookup_private(&md_cd, MD_UNIT(bp->b_dev));
  416 
  417         if (sc == NULL || sc->sc_type == MD_UNCONFIGURED) {
  418                 bp->b_error = ENXIO;
  419                 goto done;
  420         }
  421 
  422         mutex_enter(&sc->sc_lock);
  423 
  424         switch (sc->sc_type) {
  425 #if MEMORY_DISK_SERVER
  426         case MD_UMEM_SERVER:
  427                 /* Just add this job to the server's queue. */
  428                 bufq_put(sc->sc_buflist, bp);
  429                 cv_signal(&sc->sc_cv);
  430                 mutex_exit(&sc->sc_lock);
  431                 /* see md_server_loop() */
  432                 /* no biodone in this case */
  433                 return;
  434 #endif  /* MEMORY_DISK_SERVER */
  435 
  436         case MD_KMEM_FIXED:
  437         case MD_KMEM_ALLOCATED:
  438                 /* These are in kernel space.  Access directly. */
  439                 is_read = ((bp->b_flags & B_READ) == B_READ);
  440                 bp->b_resid = bp->b_bcount;
  441                 off = (bp->b_blkno << DEV_BSHIFT);
  442                 if (off >= sc->sc_size) {
  443                         if (is_read)
  444                                 break;  /* EOF */
  445                         goto set_eio;
  446                 }
  447                 xfer = bp->b_resid;
  448                 if (xfer > (sc->sc_size - off))
  449                         xfer = (sc->sc_size - off);
  450                 addr = (char *)sc->sc_addr + off;
  451                 disk_busy(&sc->sc_dkdev);
  452                 if (is_read)
  453                         memcpy(bp->b_data, addr, xfer);
  454                 else
  455                         memcpy(addr, bp->b_data, xfer);
  456                 disk_unbusy(&sc->sc_dkdev, xfer, is_read);
  457                 bp->b_resid -= xfer;
  458                 break;
  459 
  460         default:
  461                 bp->b_resid = bp->b_bcount;
  462         set_eio:
  463                 bp->b_error = EIO;
  464                 break;
  465         }
  466         mutex_exit(&sc->sc_lock);
  467 
  468  done:
  469 
  470         biodone(bp);
  471 }
  472 
  473 static int
  474 mdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
  475 {
  476         struct md_softc *sc;
  477         struct md_conf *umd;
  478         int error;
  479 
  480         if ((sc = device_lookup_private(&md_cd, MD_UNIT(dev))) == NULL)
  481                 return ENXIO;
  482 
  483         if (sc->sc_type != MD_UNCONFIGURED) {
  484                 error = disk_ioctl(&sc->sc_dkdev, dev, cmd, data, flag, l); 
  485                 if (error != EPASSTHROUGH) {
  486                         return error;
  487                 }
  488         }
  489 
  490         /* If this is not the raw partition, punt! */
  491         if (DISKPART(dev) != RAW_PART) {
  492                 return ENOTTY;
  493         }
  494 
  495         mutex_enter(&sc->sc_lock);
  496         umd = (struct md_conf *)data;
  497         error = EINVAL;
  498         switch (cmd) {
  499         case MD_GETCONF:
  500                 *umd = sc->sc_md;
  501                 error = 0;
  502                 break;
  503 
  504         case MD_SETCONF:
  505                 /* Can only set it once. */
  506                 if (sc->sc_type != MD_UNCONFIGURED)
  507                         break;
  508                 switch (umd->md_type) {
  509                 case MD_KMEM_ALLOCATED:
  510                         error = md_ioctl_kalloc(sc, umd, l);
  511                         break;
  512 #if MEMORY_DISK_SERVER
  513                 case MD_UMEM_SERVER:
  514                         error = md_ioctl_server(sc, umd, l);
  515                         break;
  516 #endif  /* MEMORY_DISK_SERVER */
  517                 default:
  518                         break;
  519                 }
  520                 break;
  521         }
  522         mutex_exit(&sc->sc_lock);
  523         return error;
  524 }
  525 
  526 static void
  527 md_set_disklabel(struct md_softc *sc)
  528 {
  529         struct disk_geom *dg = &sc->sc_dkdev.dk_geom;
  530         struct disklabel *lp = sc->sc_dkdev.dk_label;
  531         struct partition *pp;
  532 
  533         memset(lp, 0, sizeof(*lp));
  534 
  535         lp->d_secsize = DEV_BSIZE;
  536         lp->d_secperunit = sc->sc_size / DEV_BSIZE;
  537         if (lp->d_secperunit >= (32*64)) {
  538                 lp->d_nsectors = 32;
  539                 lp->d_ntracks = 64;
  540                 lp->d_ncylinders = lp->d_secperunit / (32*64);
  541         } else {
  542                 lp->d_nsectors = 1;
  543                 lp->d_ntracks = 1;
  544                 lp->d_ncylinders = lp->d_secperunit;
  545         }
  546         lp->d_secpercyl = lp->d_ntracks*lp->d_nsectors;
  547 
  548         strncpy(lp->d_typename, md_cd.cd_name, sizeof(lp->d_typename));
  549         lp->d_type = DKTYPE_MD;
  550         strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
  551         lp->d_rpm = 3600;
  552         lp->d_interleave = 1;
  553         lp->d_flags = 0;
  554 
  555         pp = &lp->d_partitions[0];
  556         pp->p_offset = 0;
  557         pp->p_size = lp->d_secperunit;
  558         pp->p_fstype = FS_BSDFFS;
  559 
  560         pp = &lp->d_partitions[RAW_PART];
  561         pp->p_offset = 0;
  562         pp->p_size = lp->d_secperunit;
  563         pp->p_fstype = FS_UNUSED;
  564 
  565         lp->d_npartitions = RAW_PART+1;
  566         lp->d_magic = DISKMAGIC;
  567         lp->d_magic2 = DISKMAGIC;
  568         lp->d_checksum = dkcksum(lp);
  569 
  570         memset(dg, 0, sizeof(*dg));
  571 
  572         dg->dg_secsize = lp->d_secsize;
  573         dg->dg_secperunit = lp->d_secperunit;
  574         dg->dg_nsectors = lp->d_nsectors;
  575         dg->dg_ntracks = lp->d_ntracks = 64;
  576         dg->dg_ncylinders = lp->d_ncylinders;
  577 
  578         disk_set_info(sc->sc_dev, &sc->sc_dkdev, NULL);
  579 }
  580 
  581 /*
  582  * Handle ioctl MD_SETCONF for (sc_type == MD_KMEM_ALLOCATED)
  583  * Just allocate some kernel memory and return.
  584  */
  585 static int
  586 md_ioctl_kalloc(struct md_softc *sc, struct md_conf *umd,
  587     struct lwp *l)
  588 {
  589         vaddr_t addr;
  590         vsize_t size;
  591 
  592         /* Sanity check the size. */
  593         size = umd->md_size;
  594         if (size < DEV_BSIZE || (size % DEV_BSIZE) != 0)
  595                 return EINVAL;
  596 
  597         mutex_exit(&sc->sc_lock);
  598 
  599         addr = uvm_km_alloc(kernel_map, size, 0, UVM_KMF_WIRED|UVM_KMF_ZERO);
  600 
  601         mutex_enter(&sc->sc_lock);
  602 
  603         if (!addr)
  604                 return ENOMEM;
  605 
  606         /* If another thread beat us to configure this unit:  fail. */
  607         if (sc->sc_type != MD_UNCONFIGURED) {
  608                 uvm_km_free(kernel_map, addr, size, UVM_KMF_WIRED);
  609                 return EINVAL;
  610         }
  611 
  612         /* This unit is now configured. */
  613         sc->sc_addr = (void *)addr;     /* kernel space */
  614         sc->sc_size = (size_t)size;
  615         sc->sc_type = MD_KMEM_ALLOCATED;
  616         md_set_disklabel(sc);
  617         return 0;
  618 }
  619 
  620 #if MEMORY_DISK_SERVER
  621 
  622 /*
  623  * Handle ioctl MD_SETCONF for (sc_type == MD_UMEM_SERVER)
  624  * Set config, then become the I/O server for this unit.
  625  */
  626 static int
  627 md_ioctl_server(struct md_softc *sc, struct md_conf *umd,
  628     struct lwp *l)
  629 {
  630         vaddr_t end;
  631         int error;
  632 
  633         KASSERT(mutex_owned(&sc->sc_lock));
  634 
  635         /* Sanity check addr, size. */
  636         end = (vaddr_t) ((char *)umd->md_addr + umd->md_size);
  637 
  638         if (
  639 #ifndef _RUMPKERNEL
  640             /*
  641              * On some architectures (e.g. powerpc) rump kernel provides
  642              * "safe" low defaults which make this test fail since malloc
  643              * does return higher addresses than the "safe" default.
  644              */
  645             (end >= VM_MAXUSER_ADDRESS) ||
  646 #endif
  647             (end < ((vaddr_t) umd->md_addr)))
  648                 return EINVAL;
  649 
  650         /* This unit is now configured. */
  651         sc->sc_addr = umd->md_addr;     /* user space */
  652         sc->sc_size = umd->md_size;
  653         sc->sc_type = MD_UMEM_SERVER;
  654         md_set_disklabel(sc);
  655 
  656         /* Become the server daemon */
  657         error = md_server_loop(sc);
  658 
  659         /* This server is now going away! */
  660         sc->sc_type = MD_UNCONFIGURED;
  661         sc->sc_addr = 0;
  662         sc->sc_size = 0;
  663 
  664         return (error);
  665 }
  666 
  667 static int
  668 md_server_loop(struct md_softc *sc)
  669 {
  670         struct buf *bp;
  671         void *addr;     /* user space address */
  672         size_t off;     /* offset into "device" */
  673         size_t xfer;    /* amount to transfer */
  674         int error;
  675         bool is_read;
  676 
  677         KASSERT(mutex_owned(&sc->sc_lock));
  678 
  679         for (;;) {
  680                 /* Wait for some work to arrive. */
  681                 while ((bp = bufq_get(sc->sc_buflist)) == NULL) {
  682                         error = cv_wait_sig(&sc->sc_cv, &sc->sc_lock);
  683                         if (error)
  684                                 return error;
  685                 }
  686 
  687                 /* Do the transfer to/from user space. */
  688                 mutex_exit(&sc->sc_lock);
  689                 error = 0;
  690                 is_read = ((bp->b_flags & B_READ) == B_READ);
  691                 bp->b_resid = bp->b_bcount;
  692                 off = (bp->b_blkno << DEV_BSHIFT);
  693                 if (off >= sc->sc_size) {
  694                         if (is_read)
  695                                 goto done;      /* EOF (not an error) */
  696                         error = EIO;
  697                         goto done;
  698                 }
  699                 xfer = bp->b_resid;
  700                 if (xfer > (sc->sc_size - off))
  701                         xfer = (sc->sc_size - off);
  702                 addr = (char *)sc->sc_addr + off;
  703                 disk_busy(&sc->sc_dkdev);
  704                 if (is_read)
  705                         error = copyin(addr, bp->b_data, xfer);
  706                 else
  707                         error = copyout(bp->b_data, addr, xfer);
  708                 disk_unbusy(&sc->sc_dkdev, (error ? 0 : xfer), is_read);
  709                 if (!error)
  710                         bp->b_resid -= xfer;
  711 
  712         done:
  713                 if (error) {
  714                         bp->b_error = error;
  715                 }
  716                 biodone(bp);
  717                 mutex_enter(&sc->sc_lock);
  718         }
  719 }
  720 #endif  /* MEMORY_DISK_SERVER */

Cache object: 48e21a1e7322127006e50b414fea74dc


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.