~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/s390/mm/extmem.c

Version: ~ [ linux-5.10-rc5 ] ~ [ linux-5.9.10 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.79 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.159 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.208 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.245 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.245 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*
  3  * Author(s)......: Carsten Otte <cotte@de.ibm.com>
  4  *                  Rob M van der Heij <rvdheij@nl.ibm.com>
  5  *                  Steven Shultz <shultzss@us.ibm.com>
  6  * Bugreports.to..: <Linux390@de.ibm.com>
  7  * Copyright IBM Corp. 2002, 2004
  8  */
  9 
 10 #define KMSG_COMPONENT "extmem"
 11 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
 12 
 13 #include <linux/kernel.h>
 14 #include <linux/string.h>
 15 #include <linux/spinlock.h>
 16 #include <linux/list.h>
 17 #include <linux/slab.h>
 18 #include <linux/export.h>
 19 #include <linux/memblock.h>
 20 #include <linux/ctype.h>
 21 #include <linux/ioport.h>
 22 #include <linux/refcount.h>
 23 #include <linux/pgtable.h>
 24 #include <asm/diag.h>
 25 #include <asm/page.h>
 26 #include <asm/ebcdic.h>
 27 #include <asm/errno.h>
 28 #include <asm/extmem.h>
 29 #include <asm/cpcmd.h>
 30 #include <asm/setup.h>
 31 
 32 #define DCSS_PURGESEG   0x08
 33 #define DCSS_LOADSHRX   0x20
 34 #define DCSS_LOADNSRX   0x24
 35 #define DCSS_FINDSEGX   0x2c
 36 #define DCSS_SEGEXTX    0x38
 37 #define DCSS_FINDSEGA   0x0c
 38 
 39 struct qrange {
 40         unsigned long  start; /* last byte type */
 41         unsigned long  end;   /* last byte reserved */
 42 };
 43 
 44 struct qout64 {
 45         unsigned long segstart;
 46         unsigned long segend;
 47         int segcnt;
 48         int segrcnt;
 49         struct qrange range[6];
 50 };
 51 
 52 struct qin64 {
 53         char qopcode;
 54         char rsrv1[3];
 55         char qrcode;
 56         char rsrv2[3];
 57         char qname[8];
 58         unsigned int qoutptr;
 59         short int qoutlen;
 60 };
 61 
 62 struct dcss_segment {
 63         struct list_head list;
 64         char dcss_name[8];
 65         char res_name[16];
 66         unsigned long start_addr;
 67         unsigned long end;
 68         refcount_t ref_count;
 69         int do_nonshared;
 70         unsigned int vm_segtype;
 71         struct qrange range[6];
 72         int segcnt;
 73         struct resource *res;
 74 };
 75 
 76 static DEFINE_MUTEX(dcss_lock);
 77 static LIST_HEAD(dcss_list);
 78 static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC",
 79                                         "EW/EN-MIXED" };
 80 static int loadshr_scode = DCSS_LOADSHRX;
 81 static int loadnsr_scode = DCSS_LOADNSRX;
 82 static int purgeseg_scode = DCSS_PURGESEG;
 83 static int segext_scode = DCSS_SEGEXTX;
 84 
 85 /*
 86  * Create the 8 bytes, ebcdic VM segment name from
 87  * an ascii name.
 88  */
 89 static void
 90 dcss_mkname(char *name, char *dcss_name)
 91 {
 92         int i;
 93 
 94         for (i = 0; i < 8; i++) {
 95                 if (name[i] == '\0')
 96                         break;
 97                 dcss_name[i] = toupper(name[i]);
 98         }
 99         for (; i < 8; i++)
100                 dcss_name[i] = ' ';
101         ASCEBC(dcss_name, 8);
102 }
103 
104 
105 /*
106  * search all segments in dcss_list, and return the one
107  * namend *name. If not found, return NULL.
108  */
109 static struct dcss_segment *
110 segment_by_name (char *name)
111 {
112         char dcss_name[9];
113         struct list_head *l;
114         struct dcss_segment *tmp, *retval = NULL;
115 
116         BUG_ON(!mutex_is_locked(&dcss_lock));
117         dcss_mkname (name, dcss_name);
118         list_for_each (l, &dcss_list) {
119                 tmp = list_entry (l, struct dcss_segment, list);
120                 if (memcmp(tmp->dcss_name, dcss_name, 8) == 0) {
121                         retval = tmp;
122                         break;
123                 }
124         }
125         return retval;
126 }
127 
128 
129 /*
130  * Perform a function on a dcss segment.
131  */
132 static inline int
133 dcss_diag(int *func, void *parameter,
134            unsigned long *ret1, unsigned long *ret2)
135 {
136         unsigned long rx, ry;
137         int rc;
138 
139         rx = (unsigned long) parameter;
140         ry = (unsigned long) *func;
141 
142         diag_stat_inc(DIAG_STAT_X064);
143         asm volatile(
144                 "       diag    %0,%1,0x64\n"
145                 "       ipm     %2\n"
146                 "       srl     %2,28\n"
147                 : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc");
148         *ret1 = rx;
149         *ret2 = ry;
150         return rc;
151 }
152 
153 static inline int
154 dcss_diag_translate_rc (int vm_rc) {
155         if (vm_rc == 44)
156                 return -ENOENT;
157         return -EIO;
158 }
159 
160 
161 /* do a diag to get info about a segment.
162  * fills start_address, end and vm_segtype fields
163  */
164 static int
165 query_segment_type (struct dcss_segment *seg)
166 {
167         unsigned long dummy, vmrc;
168         int diag_cc, rc, i;
169         struct qout64 *qout;
170         struct qin64 *qin;
171 
172         qin = kmalloc(sizeof(*qin), GFP_KERNEL | GFP_DMA);
173         qout = kmalloc(sizeof(*qout), GFP_KERNEL | GFP_DMA);
174         if ((qin == NULL) || (qout == NULL)) {
175                 rc = -ENOMEM;
176                 goto out_free;
177         }
178 
179         /* initialize diag input parameters */
180         qin->qopcode = DCSS_FINDSEGA;
181         qin->qoutptr = (unsigned long) qout;
182         qin->qoutlen = sizeof(struct qout64);
183         memcpy (qin->qname, seg->dcss_name, 8);
184 
185         diag_cc = dcss_diag(&segext_scode, qin, &dummy, &vmrc);
186 
187         if (diag_cc < 0) {
188                 rc = diag_cc;
189                 goto out_free;
190         }
191         if (diag_cc > 1) {
192                 pr_warn("Querying a DCSS type failed with rc=%ld\n", vmrc);
193                 rc = dcss_diag_translate_rc (vmrc);
194                 goto out_free;
195         }
196 
197         if (qout->segcnt > 6) {
198                 rc = -EOPNOTSUPP;
199                 goto out_free;
200         }
201 
202         if (qout->segcnt == 1) {
203                 seg->vm_segtype = qout->range[0].start & 0xff;
204         } else {
205                 /* multi-part segment. only one type supported here:
206                     - all parts are contiguous
207                     - all parts are either EW or EN type
208                     - maximum 6 parts allowed */
209                 unsigned long start = qout->segstart >> PAGE_SHIFT;
210                 for (i=0; i<qout->segcnt; i++) {
211                         if (((qout->range[i].start & 0xff) != SEG_TYPE_EW) &&
212                             ((qout->range[i].start & 0xff) != SEG_TYPE_EN)) {
213                                 rc = -EOPNOTSUPP;
214                                 goto out_free;
215                         }
216                         if (start != qout->range[i].start >> PAGE_SHIFT) {
217                                 rc = -EOPNOTSUPP;
218                                 goto out_free;
219                         }
220                         start = (qout->range[i].end >> PAGE_SHIFT) + 1;
221                 }
222                 seg->vm_segtype = SEG_TYPE_EWEN;
223         }
224 
225         /* analyze diag output and update seg */
226         seg->start_addr = qout->segstart;
227         seg->end = qout->segend;
228 
229         memcpy (seg->range, qout->range, 6*sizeof(struct qrange));
230         seg->segcnt = qout->segcnt;
231 
232         rc = 0;
233 
234  out_free:
235         kfree(qin);
236         kfree(qout);
237         return rc;
238 }
239 
240 /*
241  * get info about a segment
242  * possible return values:
243  * -ENOSYS  : we are not running on VM
244  * -EIO     : could not perform query diagnose
245  * -ENOENT  : no such segment
246  * -EOPNOTSUPP: multi-part segment cannot be used with linux
247  * -ENOMEM  : out of memory
248  * 0 .. 6   : type of segment as defined in include/asm-s390/extmem.h
249  */
250 int
251 segment_type (char* name)
252 {
253         int rc;
254         struct dcss_segment seg;
255 
256         if (!MACHINE_IS_VM)
257                 return -ENOSYS;
258 
259         dcss_mkname(name, seg.dcss_name);
260         rc = query_segment_type (&seg);
261         if (rc < 0)
262                 return rc;
263         return seg.vm_segtype;
264 }
265 
266 /*
267  * check if segment collides with other segments that are currently loaded
268  * returns 1 if this is the case, 0 if no collision was found
269  */
270 static int
271 segment_overlaps_others (struct dcss_segment *seg)
272 {
273         struct list_head *l;
274         struct dcss_segment *tmp;
275 
276         BUG_ON(!mutex_is_locked(&dcss_lock));
277         list_for_each(l, &dcss_list) {
278                 tmp = list_entry(l, struct dcss_segment, list);
279                 if ((tmp->start_addr >> 20) > (seg->end >> 20))
280                         continue;
281                 if ((tmp->end >> 20) < (seg->start_addr >> 20))
282                         continue;
283                 if (seg == tmp)
284                         continue;
285                 return 1;
286         }
287         return 0;
288 }
289 
290 /*
291  * real segment loading function, called from segment_load
292  */
293 static int
294 __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long *end)
295 {
296         unsigned long start_addr, end_addr, dummy;
297         struct dcss_segment *seg;
298         int rc, diag_cc;
299 
300         start_addr = end_addr = 0;
301         seg = kmalloc(sizeof(*seg), GFP_KERNEL | GFP_DMA);
302         if (seg == NULL) {
303                 rc = -ENOMEM;
304                 goto out;
305         }
306         dcss_mkname (name, seg->dcss_name);
307         rc = query_segment_type (seg);
308         if (rc < 0)
309                 goto out_free;
310 
311         if (segment_overlaps_others(seg)) {
312                 rc = -EBUSY;
313                 goto out_free;
314         }
315 
316         seg->res = kzalloc(sizeof(struct resource), GFP_KERNEL);
317         if (seg->res == NULL) {
318                 rc = -ENOMEM;
319                 goto out_free;
320         }
321         seg->res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
322         seg->res->start = seg->start_addr;
323         seg->res->end = seg->end;
324         memcpy(&seg->res_name, seg->dcss_name, 8);
325         EBCASC(seg->res_name, 8);
326         seg->res_name[8] = '\0';
327         strlcat(seg->res_name, " (DCSS)", sizeof(seg->res_name));
328         seg->res->name = seg->res_name;
329         rc = seg->vm_segtype;
330         if (rc == SEG_TYPE_SC ||
331             ((rc == SEG_TYPE_SR || rc == SEG_TYPE_ER) && !do_nonshared))
332                 seg->res->flags |= IORESOURCE_READONLY;
333 
334         /* Check for overlapping resources before adding the mapping. */
335         if (request_resource(&iomem_resource, seg->res)) {
336                 rc = -EBUSY;
337                 goto out_free_resource;
338         }
339 
340         rc = vmem_add_mapping(seg->start_addr, seg->end - seg->start_addr + 1);
341         if (rc)
342                 goto out_resource;
343 
344         if (do_nonshared)
345                 diag_cc = dcss_diag(&loadnsr_scode, seg->dcss_name,
346                                 &start_addr, &end_addr);
347         else
348                 diag_cc = dcss_diag(&loadshr_scode, seg->dcss_name,
349                                 &start_addr, &end_addr);
350         if (diag_cc < 0) {
351                 dcss_diag(&purgeseg_scode, seg->dcss_name,
352                                 &dummy, &dummy);
353                 rc = diag_cc;
354                 goto out_mapping;
355         }
356         if (diag_cc > 1) {
357                 pr_warn("Loading DCSS %s failed with rc=%ld\n", name, end_addr);
358                 rc = dcss_diag_translate_rc(end_addr);
359                 dcss_diag(&purgeseg_scode, seg->dcss_name,
360                                 &dummy, &dummy);
361                 goto out_mapping;
362         }
363         seg->start_addr = start_addr;
364         seg->end = end_addr;
365         seg->do_nonshared = do_nonshared;
366         refcount_set(&seg->ref_count, 1);
367         list_add(&seg->list, &dcss_list);
368         *addr = seg->start_addr;
369         *end  = seg->end;
370         if (do_nonshared)
371                 pr_info("DCSS %s of range %px to %px and type %s loaded as "
372                         "exclusive-writable\n", name, (void*) seg->start_addr,
373                         (void*) seg->end, segtype_string[seg->vm_segtype]);
374         else {
375                 pr_info("DCSS %s of range %px to %px and type %s loaded in "
376                         "shared access mode\n", name, (void*) seg->start_addr,
377                         (void*) seg->end, segtype_string[seg->vm_segtype]);
378         }
379         goto out;
380  out_mapping:
381         vmem_remove_mapping(seg->start_addr, seg->end - seg->start_addr + 1);
382  out_resource:
383         release_resource(seg->res);
384  out_free_resource:
385         kfree(seg->res);
386  out_free:
387         kfree(seg);
388  out:
389         return rc;
390 }
391 
392 /*
393  * this function loads a DCSS segment
394  * name         : name of the DCSS
395  * do_nonshared : 0 indicates that the dcss should be shared with other linux images
396  *                1 indicates that the dcss should be exclusive for this linux image
397  * addr         : will be filled with start address of the segment
398  * end          : will be filled with end address of the segment
399  * return values:
400  * -ENOSYS  : we are not running on VM
401  * -EIO     : could not perform query or load diagnose
402  * -ENOENT  : no such segment
403  * -EOPNOTSUPP: multi-part segment cannot be used with linux
404  * -EBUSY   : segment cannot be used (overlaps with dcss or storage)
405  * -ERANGE  : segment cannot be used (exceeds kernel mapping range)
406  * -EPERM   : segment is currently loaded with incompatible permissions
407  * -ENOMEM  : out of memory
408  * 0 .. 6   : type of segment as defined in include/asm-s390/extmem.h
409  */
410 int
411 segment_load (char *name, int do_nonshared, unsigned long *addr,
412                 unsigned long *end)
413 {
414         struct dcss_segment *seg;
415         int rc;
416 
417         if (!MACHINE_IS_VM)
418                 return -ENOSYS;
419 
420         mutex_lock(&dcss_lock);
421         seg = segment_by_name (name);
422         if (seg == NULL)
423                 rc = __segment_load (name, do_nonshared, addr, end);
424         else {
425                 if (do_nonshared == seg->do_nonshared) {
426                         refcount_inc(&seg->ref_count);
427                         *addr = seg->start_addr;
428                         *end  = seg->end;
429                         rc    = seg->vm_segtype;
430                 } else {
431                         *addr = *end = 0;
432                         rc    = -EPERM;
433                 }
434         }
435         mutex_unlock(&dcss_lock);
436         return rc;
437 }
438 
439 /*
440  * this function modifies the shared state of a DCSS segment. note that
441  * name         : name of the DCSS
442  * do_nonshared : 0 indicates that the dcss should be shared with other linux images
443  *                1 indicates that the dcss should be exclusive for this linux image
444  * return values:
445  * -EIO     : could not perform load diagnose (segment gone!)
446  * -ENOENT  : no such segment (segment gone!)
447  * -EAGAIN  : segment is in use by other exploiters, try later
448  * -EINVAL  : no segment with the given name is currently loaded - name invalid
449  * -EBUSY   : segment can temporarily not be used (overlaps with dcss)
450  * 0        : operation succeeded
451  */
452 int
453 segment_modify_shared (char *name, int do_nonshared)
454 {
455         struct dcss_segment *seg;
456         unsigned long start_addr, end_addr, dummy;
457         int rc, diag_cc;
458 
459         start_addr = end_addr = 0;
460         mutex_lock(&dcss_lock);
461         seg = segment_by_name (name);
462         if (seg == NULL) {
463                 rc = -EINVAL;
464                 goto out_unlock;
465         }
466         if (do_nonshared == seg->do_nonshared) {
467                 pr_info("DCSS %s is already in the requested access "
468                         "mode\n", name);
469                 rc = 0;
470                 goto out_unlock;
471         }
472         if (refcount_read(&seg->ref_count) != 1) {
473                 pr_warn("DCSS %s is in use and cannot be reloaded\n", name);
474                 rc = -EAGAIN;
475                 goto out_unlock;
476         }
477         release_resource(seg->res);
478         if (do_nonshared)
479                 seg->res->flags &= ~IORESOURCE_READONLY;
480         else
481                 if (seg->vm_segtype == SEG_TYPE_SR ||
482                     seg->vm_segtype == SEG_TYPE_ER)
483                         seg->res->flags |= IORESOURCE_READONLY;
484 
485         if (request_resource(&iomem_resource, seg->res)) {
486                 pr_warn("DCSS %s overlaps with used memory resources and cannot be reloaded\n",
487                         name);
488                 rc = -EBUSY;
489                 kfree(seg->res);
490                 goto out_del_mem;
491         }
492 
493         dcss_diag(&purgeseg_scode, seg->dcss_name, &dummy, &dummy);
494         if (do_nonshared)
495                 diag_cc = dcss_diag(&loadnsr_scode, seg->dcss_name,
496                                 &start_addr, &end_addr);
497         else
498                 diag_cc = dcss_diag(&loadshr_scode, seg->dcss_name,
499                                 &start_addr, &end_addr);
500         if (diag_cc < 0) {
501                 rc = diag_cc;
502                 goto out_del_res;
503         }
504         if (diag_cc > 1) {
505                 pr_warn("Reloading DCSS %s failed with rc=%ld\n",
506                         name, end_addr);
507                 rc = dcss_diag_translate_rc(end_addr);
508                 goto out_del_res;
509         }
510         seg->start_addr = start_addr;
511         seg->end = end_addr;
512         seg->do_nonshared = do_nonshared;
513         rc = 0;
514         goto out_unlock;
515  out_del_res:
516         release_resource(seg->res);
517         kfree(seg->res);
518  out_del_mem:
519         vmem_remove_mapping(seg->start_addr, seg->end - seg->start_addr + 1);
520         list_del(&seg->list);
521         dcss_diag(&purgeseg_scode, seg->dcss_name, &dummy, &dummy);
522         kfree(seg);
523  out_unlock:
524         mutex_unlock(&dcss_lock);
525         return rc;
526 }
527 
528 /*
529  * Decrease the use count of a DCSS segment and remove
530  * it from the address space if nobody is using it
531  * any longer.
532  */
533 void
534 segment_unload(char *name)
535 {
536         unsigned long dummy;
537         struct dcss_segment *seg;
538 
539         if (!MACHINE_IS_VM)
540                 return;
541 
542         mutex_lock(&dcss_lock);
543         seg = segment_by_name (name);
544         if (seg == NULL) {
545                 pr_err("Unloading unknown DCSS %s failed\n", name);
546                 goto out_unlock;
547         }
548         if (!refcount_dec_and_test(&seg->ref_count))
549                 goto out_unlock;
550         release_resource(seg->res);
551         kfree(seg->res);
552         vmem_remove_mapping(seg->start_addr, seg->end - seg->start_addr + 1);
553         list_del(&seg->list);
554         dcss_diag(&purgeseg_scode, seg->dcss_name, &dummy, &dummy);
555         kfree(seg);
556 out_unlock:
557         mutex_unlock(&dcss_lock);
558 }
559 
560 /*
561  * save segment content permanently
562  */
563 void
564 segment_save(char *name)
565 {
566         struct dcss_segment *seg;
567         char cmd1[160];
568         char cmd2[80];
569         int i, response;
570 
571         if (!MACHINE_IS_VM)
572                 return;
573 
574         mutex_lock(&dcss_lock);
575         seg = segment_by_name (name);
576 
577         if (seg == NULL) {
578                 pr_err("Saving unknown DCSS %s failed\n", name);
579                 goto out;
580         }
581 
582         sprintf(cmd1, "DEFSEG %s", name);
583         for (i=0; i<seg->segcnt; i++) {
584                 sprintf(cmd1+strlen(cmd1), " %lX-%lX %s",
585                         seg->range[i].start >> PAGE_SHIFT,
586                         seg->range[i].end >> PAGE_SHIFT,
587                         segtype_string[seg->range[i].start & 0xff]);
588         }
589         sprintf(cmd2, "SAVESEG %s", name);
590         response = 0;
591         cpcmd(cmd1, NULL, 0, &response);
592         if (response) {
593                 pr_err("Saving a DCSS failed with DEFSEG response code "
594                        "%i\n", response);
595                 goto out;
596         }
597         cpcmd(cmd2, NULL, 0, &response);
598         if (response) {
599                 pr_err("Saving a DCSS failed with SAVESEG response code "
600                        "%i\n", response);
601                 goto out;
602         }
603 out:
604         mutex_unlock(&dcss_lock);
605 }
606 
607 /*
608  * print appropriate error message for segment_load()/segment_type()
609  * return code
610  */
611 void segment_warning(int rc, char *seg_name)
612 {
613         switch (rc) {
614         case -ENOENT:
615                 pr_err("DCSS %s cannot be loaded or queried\n", seg_name);
616                 break;
617         case -ENOSYS:
618                 pr_err("DCSS %s cannot be loaded or queried without "
619                        "z/VM\n", seg_name);
620                 break;
621         case -EIO:
622                 pr_err("Loading or querying DCSS %s resulted in a "
623                        "hardware error\n", seg_name);
624                 break;
625         case -EOPNOTSUPP:
626                 pr_err("DCSS %s has multiple page ranges and cannot be "
627                        "loaded or queried\n", seg_name);
628                 break;
629         case -EBUSY:
630                 pr_err("%s needs used memory resources and cannot be "
631                        "loaded or queried\n", seg_name);
632                 break;
633         case -EPERM:
634                 pr_err("DCSS %s is already loaded in a different access "
635                        "mode\n", seg_name);
636                 break;
637         case -ENOMEM:
638                 pr_err("There is not enough memory to load or query "
639                        "DCSS %s\n", seg_name);
640                 break;
641         case -ERANGE:
642                 pr_err("DCSS %s exceeds the kernel mapping range (%lu) "
643                        "and cannot be loaded\n", seg_name, VMEM_MAX_PHYS);
644                 break;
645         default:
646                 break;
647         }
648 }
649 
650 EXPORT_SYMBOL(segment_load);
651 EXPORT_SYMBOL(segment_unload);
652 EXPORT_SYMBOL(segment_save);
653 EXPORT_SYMBOL(segment_type);
654 EXPORT_SYMBOL(segment_modify_shared);
655 EXPORT_SYMBOL(segment_warning);
656 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp