Print this page
7882 Add /dev/full , the always-full memory device
Reviewed by: Adam Stevko <adam.stevko@gmail.com>
Reviewed by: Toomas Soome <tsoome@me.com>


   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  * Copyright (c) 2015, Joyent, Inc.  All rights reserved.

  28  */
  29 
  30 /*
  31  * Memory special file
  32  */
  33 
  34 #include <sys/types.h>
  35 #include <sys/param.h>
  36 #include <sys/user.h>
  37 #include <sys/buf.h>
  38 #include <sys/systm.h>
  39 #include <sys/cred.h>
  40 #include <sys/vm.h>
  41 #include <sys/uio.h>
  42 #include <sys/mman.h>
  43 #include <sys/kmem.h>
  44 #include <vm/seg.h>
  45 #include <vm/page.h>
  46 #include <sys/stat.h>
  47 #include <sys/vmem.h>


 143 }
 144 
 145 /*ARGSUSED1*/
 146 static int
 147 mm_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
 148 {
 149         int i;
 150         struct mem_minor {
 151                 char *name;
 152                 minor_t minor;
 153                 int privonly;
 154                 const char *rdpriv;
 155                 const char *wrpriv;
 156                 mode_t priv_mode;
 157         } mm[] = {
 158                 { "mem",        M_MEM,          0,      NULL,   "all",  0640 },
 159                 { "kmem",       M_KMEM,         0,      NULL,   "all",  0640 },
 160                 { "allkmem",    M_ALLKMEM,      0,      "all",  "all",  0600 },
 161                 { "null",       M_NULL, PRIVONLY_DEV,   NULL,   NULL,   0666 },
 162                 { "zero",       M_ZERO, PRIVONLY_DEV,   NULL,   NULL,   0666 },

 163         };
 164         kstat_t *ksp;
 165 
 166         mutex_init(&mm_lock, NULL, MUTEX_DEFAULT, NULL);
 167         mm_map = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP);
 168 
 169         for (i = 0; i < (sizeof (mm) / sizeof (mm[0])); i++) {
 170                 if (ddi_create_priv_minor_node(devi, mm[i].name, S_IFCHR,
 171                     mm[i].minor, DDI_PSEUDO, mm[i].privonly,
 172                     mm[i].rdpriv, mm[i].wrpriv, mm[i].priv_mode) ==
 173                     DDI_FAILURE) {
 174                         ddi_remove_minor_node(devi, NULL);
 175                         return (DDI_FAILURE);
 176                 }
 177         }
 178 
 179         mm_dip = devi;
 180 
 181         ksp = kstat_create("mm", 0, "phys_installed", "misc",
 182             KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VAR_SIZE | KSTAT_FLAG_VIRTUAL);


 204                 *result = (void *)mm_dip;
 205                 error = DDI_SUCCESS;
 206                 break;
 207         case DDI_INFO_DEVT2INSTANCE:
 208                 *result = (void *)0;
 209                 error = DDI_SUCCESS;
 210                 break;
 211         default:
 212                 error = DDI_FAILURE;
 213         }
 214         return (error);
 215 }
 216 
 217 /*ARGSUSED1*/
 218 static int
 219 mmopen(dev_t *devp, int flag, int typ, struct cred *cred)
 220 {
 221         switch (getminor(*devp)) {
 222         case M_NULL:
 223         case M_ZERO:

 224         case M_MEM:
 225         case M_KMEM:
 226         case M_ALLKMEM:
 227                 /* standard devices */
 228                 break;
 229 
 230         default:
 231                 /* Unsupported or unknown type */
 232                 return (EINVAL);
 233         }
 234         /* must be character device */
 235         if (typ != OTYP_CHR)
 236                 return (EINVAL);
 237         return (0);
 238 }
 239 
 240 struct pollhead mm_pollhd;
 241 
 242 /*ARGSUSED*/
 243 static int
 244 mmchpoll(dev_t dev, short events, int anyyet, short *reventsp,
 245     struct pollhead **phpp)
 246 {
 247         switch (getminor(dev)) {
 248         case M_NULL:
 249         case M_ZERO:

 250         case M_MEM:
 251         case M_KMEM:
 252         case M_ALLKMEM:
 253                 *reventsp = events & (POLLIN | POLLOUT | POLLPRI | POLLRDNORM |
 254                     POLLWRNORM | POLLRDBAND | POLLWRBAND);
 255                 /*
 256                  * A non NULL pollhead pointer should be returned in case
 257                  * user polls for 0 events.
 258                  */
 259                 *phpp = !anyyet && !*reventsp ?
 260                     &mm_pollhd : (struct pollhead *)NULL;
 261                 return (0);
 262         default:
 263                 /* no other devices currently support polling */
 264                 return (ENXIO);
 265         }
 266 }
 267 
 268 static int
 269 mmpropop(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int flags,


 421                         v = hat_getpfnum(kas.a_hat,
 422                             (caddr_t)(uintptr_t)uio->uio_loffset);
 423                         if (v == PFN_INVALID) {
 424                                 if (locked)
 425                                         as_pageunlock(&kas, ppp, vaddr,
 426                                             PAGESIZE, S_WRITE);
 427                                 error = EFAULT;
 428                                 break;
 429                         }
 430 
 431                         error = mmio(uio, rw, v, uio->uio_loffset & PAGEOFFSET,
 432                             minor == M_ALLKMEM || mm_kmem_io_access,
 433                             (locked && ppp) ? *ppp : NULL);
 434                         if (locked)
 435                                 as_pageunlock(&kas, ppp, vaddr, PAGESIZE,
 436                                     S_WRITE);
 437                         }
 438 
 439                         break;
 440 








 441                 case M_ZERO:
 442                         if (rw == UIO_READ) {
 443                                 label_t ljb;
 444 
 445                                 if (on_fault(&ljb)) {
 446                                         no_fault();
 447                                         error = EFAULT;
 448                                         break;
 449                                 }
 450                                 uzero(iov->iov_base, iov->iov_len);
 451                                 no_fault();
 452                                 uio->uio_resid -= iov->iov_len;
 453                                 uio->uio_loffset += iov->iov_len;
 454                                 break;
 455                         }
 456                         /* else it's a write, fall through to NULL case */
 457                         /*FALLTHROUGH*/
 458 
 459                 case M_NULL:
 460                         if (rw == UIO_READ)


 810 
 811         switch (minor) {
 812         case M_MEM:
 813                 pf = btop(off);
 814                 memlist_read_lock();
 815                 for (pmem = phys_install; pmem != NULL; pmem = pmem->ml_next) {
 816                         if (pf >= BTOP(pmem->ml_address) &&
 817                             pf < BTOP(pmem->ml_address + pmem->ml_size)) {
 818                                 memlist_read_unlock();
 819                                 return (impl_obmem_pfnum(pf));
 820                         }
 821                 }
 822                 memlist_read_unlock();
 823                 break;
 824 
 825         case M_KMEM:
 826         case M_ALLKMEM:
 827                 /* no longer supported with KPR */
 828                 return (-1);
 829 

 830         case M_ZERO:
 831                 /*
 832                  * We shouldn't be mmap'ing to /dev/zero here as
 833                  * mmsegmap() should have already converted
 834                  * a mapping request for this device to a mapping
 835                  * using seg_vn for anonymous memory.
 836                  */
 837                 break;
 838 
 839         }
 840         return (-1);
 841 }
 842 
 843 /*
 844  * This function is called when a memory device is mmap'ed.
 845  * Set up the mapping to the correct device driver.
 846  */
 847 static int
 848 mmsegmap(dev_t dev, off_t off, struct as *as, caddr_t *addrp, off_t len,
 849     uint_t prot, uint_t maxprot, uint_t flags, struct cred *cred)




   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  * Copyright (c) 2015, Joyent, Inc.  All rights reserved.
  28  * Copyright 2017 James S Blachly, MD <james.blachly@gmail.com>
  29  */
  30 
  31 /*
  32  * Memory special file
  33  */
  34 
  35 #include <sys/types.h>
  36 #include <sys/param.h>
  37 #include <sys/user.h>
  38 #include <sys/buf.h>
  39 #include <sys/systm.h>
  40 #include <sys/cred.h>
  41 #include <sys/vm.h>
  42 #include <sys/uio.h>
  43 #include <sys/mman.h>
  44 #include <sys/kmem.h>
  45 #include <vm/seg.h>
  46 #include <vm/page.h>
  47 #include <sys/stat.h>
  48 #include <sys/vmem.h>


 144 }
 145 
 146 /*ARGSUSED1*/
 147 static int
 148 mm_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
 149 {
 150         int i;
 151         struct mem_minor {
 152                 char *name;
 153                 minor_t minor;
 154                 int privonly;
 155                 const char *rdpriv;
 156                 const char *wrpriv;
 157                 mode_t priv_mode;
 158         } mm[] = {
 159                 { "mem",        M_MEM,          0,      NULL,   "all",  0640 },
 160                 { "kmem",       M_KMEM,         0,      NULL,   "all",  0640 },
 161                 { "allkmem",    M_ALLKMEM,      0,      "all",  "all",  0600 },
 162                 { "null",       M_NULL, PRIVONLY_DEV,   NULL,   NULL,   0666 },
 163                 { "zero",       M_ZERO, PRIVONLY_DEV,   NULL,   NULL,   0666 },
 164                 { "full",       M_FULL, PRIVONLY_DEV,   NULL,   NULL,   0666 },
 165         };
 166         kstat_t *ksp;
 167 
 168         mutex_init(&mm_lock, NULL, MUTEX_DEFAULT, NULL);
 169         mm_map = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP);
 170 
 171         for (i = 0; i < (sizeof (mm) / sizeof (mm[0])); i++) {
 172                 if (ddi_create_priv_minor_node(devi, mm[i].name, S_IFCHR,
 173                     mm[i].minor, DDI_PSEUDO, mm[i].privonly,
 174                     mm[i].rdpriv, mm[i].wrpriv, mm[i].priv_mode) ==
 175                     DDI_FAILURE) {
 176                         ddi_remove_minor_node(devi, NULL);
 177                         return (DDI_FAILURE);
 178                 }
 179         }
 180 
 181         mm_dip = devi;
 182 
 183         ksp = kstat_create("mm", 0, "phys_installed", "misc",
 184             KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VAR_SIZE | KSTAT_FLAG_VIRTUAL);


 206                 *result = (void *)mm_dip;
 207                 error = DDI_SUCCESS;
 208                 break;
 209         case DDI_INFO_DEVT2INSTANCE:
 210                 *result = (void *)0;
 211                 error = DDI_SUCCESS;
 212                 break;
 213         default:
 214                 error = DDI_FAILURE;
 215         }
 216         return (error);
 217 }
 218 
 219 /*ARGSUSED1*/
 220 static int
 221 mmopen(dev_t *devp, int flag, int typ, struct cred *cred)
 222 {
 223         switch (getminor(*devp)) {
 224         case M_NULL:
 225         case M_ZERO:
 226         case M_FULL:
 227         case M_MEM:
 228         case M_KMEM:
 229         case M_ALLKMEM:
 230                 /* standard devices */
 231                 break;
 232 
 233         default:
 234                 /* Unsupported or unknown type */
 235                 return (EINVAL);
 236         }
 237         /* must be character device */
 238         if (typ != OTYP_CHR)
 239                 return (EINVAL);
 240         return (0);
 241 }
 242 
 243 struct pollhead mm_pollhd;
 244 
 245 /*ARGSUSED*/
 246 static int
 247 mmchpoll(dev_t dev, short events, int anyyet, short *reventsp,
 248     struct pollhead **phpp)
 249 {
 250         switch (getminor(dev)) {
 251         case M_NULL:
 252         case M_ZERO:
 253         case M_FULL:
 254         case M_MEM:
 255         case M_KMEM:
 256         case M_ALLKMEM:
 257                 *reventsp = events & (POLLIN | POLLOUT | POLLPRI | POLLRDNORM |
 258                     POLLWRNORM | POLLRDBAND | POLLWRBAND);
 259                 /*
 260                  * A non NULL pollhead pointer should be returned in case
 261                  * user polls for 0 events.
 262                  */
 263                 *phpp = !anyyet && !*reventsp ?
 264                     &mm_pollhd : (struct pollhead *)NULL;
 265                 return (0);
 266         default:
 267                 /* no other devices currently support polling */
 268                 return (ENXIO);
 269         }
 270 }
 271 
 272 static int
 273 mmpropop(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int flags,


 425                         v = hat_getpfnum(kas.a_hat,
 426                             (caddr_t)(uintptr_t)uio->uio_loffset);
 427                         if (v == PFN_INVALID) {
 428                                 if (locked)
 429                                         as_pageunlock(&kas, ppp, vaddr,
 430                                             PAGESIZE, S_WRITE);
 431                                 error = EFAULT;
 432                                 break;
 433                         }
 434 
 435                         error = mmio(uio, rw, v, uio->uio_loffset & PAGEOFFSET,
 436                             minor == M_ALLKMEM || mm_kmem_io_access,
 437                             (locked && ppp) ? *ppp : NULL);
 438                         if (locked)
 439                                 as_pageunlock(&kas, ppp, vaddr, PAGESIZE,
 440                                     S_WRITE);
 441                         }
 442 
 443                         break;
 444 
 445                 case M_FULL:
 446                         if (rw == UIO_WRITE) {
 447                                 error = ENOSPC;
 448                                 break;
 449                         }
 450                         /* else it's a read, fall through to zero case */
 451                         /*FALLTHROUGH*/
 452 
 453                 case M_ZERO:
 454                         if (rw == UIO_READ) {
 455                                 label_t ljb;
 456 
 457                                 if (on_fault(&ljb)) {
 458                                         no_fault();
 459                                         error = EFAULT;
 460                                         break;
 461                                 }
 462                                 uzero(iov->iov_base, iov->iov_len);
 463                                 no_fault();
 464                                 uio->uio_resid -= iov->iov_len;
 465                                 uio->uio_loffset += iov->iov_len;
 466                                 break;
 467                         }
 468                         /* else it's a write, fall through to NULL case */
 469                         /*FALLTHROUGH*/
 470 
 471                 case M_NULL:
 472                         if (rw == UIO_READ)


 822 
 823         switch (minor) {
 824         case M_MEM:
 825                 pf = btop(off);
 826                 memlist_read_lock();
 827                 for (pmem = phys_install; pmem != NULL; pmem = pmem->ml_next) {
 828                         if (pf >= BTOP(pmem->ml_address) &&
 829                             pf < BTOP(pmem->ml_address + pmem->ml_size)) {
 830                                 memlist_read_unlock();
 831                                 return (impl_obmem_pfnum(pf));
 832                         }
 833                 }
 834                 memlist_read_unlock();
 835                 break;
 836 
 837         case M_KMEM:
 838         case M_ALLKMEM:
 839                 /* no longer supported with KPR */
 840                 return (-1);
 841 
 842         case M_FULL:
 843         case M_ZERO:
 844                 /*
 845                  * We shouldn't be mmap'ing to /dev/zero here as
 846                  * mmsegmap() should have already converted
 847                  * a mapping request for this device to a mapping
 848                  * using seg_vn for anonymous memory.
 849                  */
 850                 break;
 851 
 852         }
 853         return (-1);
 854 }
 855 
 856 /*
 857  * This function is called when a memory device is mmap'ed.
 858  * Set up the mapping to the correct device driver.
 859  */
 860 static int
 861 mmsegmap(dev_t dev, off_t off, struct as *as, caddr_t *addrp, off_t len,
 862     uint_t prot, uint_t maxprot, uint_t flags, struct cred *cred)