-
Notifications
You must be signed in to change notification settings - Fork 62
/
mm_modules_091_100_kern-2.6.37.patch
1834 lines (1713 loc) · 55 KB
/
mm_modules_091_100_kern-2.6.37.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
diff --git a/Documentation/mm_modules.txt b/Documentation/mm_modules.txt
new file mode 100644
index 0000000..9afba9d
--- /dev/null
+++ b/Documentation/mm_modules.txt 2011-03-17 12:45:50.030884072 +0000
@@ -0,0 +1,284 @@
+ Virtual (MM_MODULES) and Physical (PMEM_MODULES) modules for Linux 2.6.32
+
+ Gil Tene <[email protected]>
+
+In order to support extended functionality for virtual and physical memory,
+enabling loadable modules to deliver integrated memory management
+functionality is desirable.
+
+Examples of valuable extended functionality can include:
+
+- Support for mappings with multiple and mixed page sizes
+ - Including transitioning of mapped addresses from large to small page
+ mappings, or small to large.
+- Support for very high sustained mapping modification rates:
+ - Allowing concurrent modifications within the same address space
+ - Allowing user to [safely] indicate lazy TLB invalidation and
+ thereby dramatically reduce per change costs
+ - Supporting fast, safe application of very large "batch" sets
+ of mapping modifications (remaps and mprotects), such that
+ all changes become visible within the same, extremely short
+ period of time.
+- Support for large number of disjoint mappings with arbitrary manipulations
+ at high rates
+
+In order to support such functionality, memory management modules need
+to interact with several points in the virtual and physical memory systems
+that are "lower" that those of a typical module or driver under previously
+kernel interfaces. The specific interface points are itemized below.
+
+A set of proposed patches against the RHEL 2.6.32-rc7-git1 is provided,
+which creates the appropriate interfaces for module to register with,
+allowing them to interact with vmas, mm structures and pages through
+their needed lifecycle transitions, as well as keep state they
+may need associated with vmas and mm structures.
+
+----------------------------------------------------------------------
+
+At a high level, the patches represent:
+
+Changes to existing data structures:
+
+- An added "mm_modules" field to struct mm_struct.
+
+- Two added fields to "mm_module_ops" struct vm_area_struct.
+
+New data structures:
+
+- Four new common data types (struct mm_module_struct,
+ struct pmem_module_struct, struct pmem_module_operations_struct,
+ mm_module_operations_struct)
+
+Code changes:
+
+- changes to add calls into mm_module_ops and pmem_module_ops at
+ various appropriate locations.
+
+- changes to disable or make invalid certain operations (e.g. vma
+ split, merge, remap) for vmas that are controlled by mm_modules
+
+- A change to fault handling to allow handle_mm_fault to return
+ an indication for SEGV_MAPERR or SEGV_ACCERR (allow for sparsely
+ mapped, and non-homogeneously protected vmas).
+
+- A change to gup_fast (arch/x86/mm/gup.c) to make it safely independent
+ of any page table locking and invalidation schemes (as long as whatever
+ they do is safe in an SMP environment), including mechanisms that
+ may ref-count pages down to 0 before tlb-invalidating their mappings.
+
+----------------------------------------------------------------------
+Note: about need for physical memory support:
+
+While virtual memory functionality alone can support some of the
+possible extended functionality, high performance functionality
+requires physical memory management and control as well. A good example
+of this is in-process recycling of memory and in-process memory free
+lists and their use in dramatically dampening TLB invalidate requirements
+on allocation or deallocation edges. When a system need to sustain
+a high rate of new mappings (e.g. 20GB/sec of sustained random, disjoint
+map/remap/unmap operations), such in-process physical memory free lists
+become a must.
+
+----------------------------------------------------------------------
+Note: About hugetlb
+
+To increase the likelihood of usefulness to generic virtual memory
+functionality additions, the module interface was designed such that
+the all current hugetlb functionality could be developed as a loadable
+kernel module under the proposed interface.
+
+----------------------------------------------------------------------
+
+Some high level design points:
+
+- Virtual memory modules (mm_modules) are generally responsible for
+creating and controlling their own vmas. [whole] vmas can be torn down
+by the kernel.
+
+- The kernel's "normal" memory manipulation system calls will not modify
+the bounds of an mm_module managed vma. [i.e. no merging, no splitting,
+no remapping]. mm_modules may support such functionality through their own
+entry points.
+
+- mm_modules must adhere to the kernel's convention for locking the
+page table hierarchy for any part of the hierarchy that may be manipulated
+by other code. While mm_modules may apply private locking schemes
+to parts of the hierarchy (e.g. below the pmd level), they must do
+so only with parts of the hierarchy that are know to be completely owned
+by the module. [e.g. 2MB aligned vmas can separately control locking at
+the pmd level and below]
+
+- mm_modules can carry unique state per mm, and unique state per vma.
+
+- mm_modules provide their own fault handling functionality. They may
+ indicate a need to SEGV with a mapping or protection si_code (sparsely
+ mapped vas are a good example of this need).
+
+- pmem_modules manage their own lists of physical pages, and are expected
+ to be aware of physical pages that they are supposed to control, even
+ when (and especially when) those pages carry a 0 ref count.. They can
+ do so in any way they want (e.g. a module-private vmemmap mirror, or
+ one using much larger aligned page sizes).
+
+- registered pmem_modules intercept all physical page releases at
+ put_page() and release_pages(), such that when a page is ref-counted down
+ to 0, the pmem_module would pick it up before it reaches the system's
+ normal free lists.
+
+- pmem_modules are expected to support hot_plug functionality. When physical
+ memory is added to the system, all current pmem_modules must adjust their
+ internal maps of physical memory to be able to correctly handle physical
+ pages of the newly discovered range.
+
+----------------------------------------------------------------------
+Virtual Memory Module Interface Points:
+
+Fault handling:
+ int (*handle_mm_fault)(struct mm_struct *mm,
+ struct vm_area_struct *vma, unsigned long addr,
+ int write_access);
+
+ Called from handle_mm_fault() for vmas managed by the mm_module to
+ satisfy fault handling needs. May return an indication of SEGV_ACCERR
+ or SEGV_MAPERR if fault address is not mapped (e.g. for sparsely
+ populated vmas).
+
+Protection changes:
+ int (*change_protection)(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end, unsigned long newflags);
+
+ Called from mprotect_fixup() to change the protection of all mapped
+ pages within a vma managed by the mm_module. [needed for e.g. hugetlb
+ interaction with mprotect()]. Note: the module may (and likely will)
+ provide it's own, finer grain protection control calls.
+
+Page range duplication:
+ int (*copy_page_range)(struct mm_struct *dst_mm,
+ struct mm_struct *src_mm, struct vm_area_struct *vma);
+
+ Called from copy_page_range() to duplicate a vma managed by an mm_module
+ from a src_mm to a dst_mm. Used for specialized forking behavior.
+
+Page following:
+ int (*follow_page)(struct mm_struct *mm, struct vm_area_struct *vma,
+ struct page **pages, struct vm_area_struct **vmas,
+ unsigned long *position, int *length,
+ int i, int write);
+
+ Called from get_user_pages() to get a vector of pages associated with a
+ range of addresses within a vma managed by the mm_module. Required
+ for core dumping, gdb, etc.
+
+Probe mapping protection and range:
+ int (*probe_mapped)(struct vm_area_struct *vma, unsigned long start,
+ unsigned long *end_range, unsigned long *range_vm_flags);
+
+ return an indication of whether an address within a vma is mapped or
+ not, along with it's protection and the range of identical protection
+ mapping. Used by core dump functionality (e.g. elf_core_dump()) for
+ efficient traversal and dumping of very large and sparsely populated
+ vmas (e.g. 16TB vma containing 300MB of mapped data).
+
+Unmapping:
+ unsigned long (*unmap_page_range)(struct mmu_gather **tlbp,
+ struct vm_area_struct *vma, unsigned long addr,
+ unsigned long end, long *zap_work,
+ struct zap_details *details);
+
+ Called by unmap_vmas() to unmap and release all pages with a vma
+ managed by the mm_module.
+
+ void (*free_pgd_range)(struct mmu_gather *tlb, unsigned long addr,
+ unsigned long end, unsigned long floor,
+ unsigned long ceiling);
+
+ Called by free_pgtables() to tear down all page table hierarchy
+ storage associated with a vma managed by the mm_module.
+
+vma lifecycle:
+ int (*init_module_vma)(struct vm_area_struct *vma,
+ struct vm_area_struct *old_vma);
+
+ Called by dup_mmap() to initialize the mm_module state associated with
+ a newly duplicated vma managed by the mm_module.
+
+ void (*exit_module_vma)(struct vm_area_struct *vma);
+
+ Called by remove_vma() to tear down the mm_module state associated with
+ the vma managed by the mm_module.
+
+mm lifecycle:
+ int (*init_module_mm)(struct mm_struct *mm,
+ struct mm_module_struct *mm_mod);
+
+ Called from mm_init to initialize the mm_module state associated with a
+ newly duplicated mm.
+
+ int (*exit_module_mm)(struct mm_struct *mm,
+ struct mm_module_struct *mm_mod);
+
+ Called by mmput to tear down the mm_module state associated with an mm
+
+struct mm_module_operations_struct {
+ int (*handle_mm_fault)(struct mm_struct *mm,
+ struct vm_area_struct *vma, unsigned long addr,
+ int write_access);
+ int (*change_protection)(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end, unsigned long newflags);
+ int (*copy_page_range)(struct mm_struct *dst_mm,
+ struct mm_struct *src_mm, struct vm_area_struct *vma);
+ int (*follow_page)(struct mm_struct *mm, struct vm_area_struct *vma,
+ struct page **pages, struct vm_area_struct **vmas,
+ unsigned long *position, int *length,
+ int i, int write);
+ int (*probe_mapped)(struct vm_area_struct *vma, unsigned long start,
+ unsigned long *end_range, unsigned long *range_vm_flags);
+ unsigned long (*unmap_page_range)(struct mmu_gather **tlbp,
+ struct vm_area_struct *vma, unsigned long addr,
+ unsigned long end, long *zap_work,
+ struct zap_details *details);
+ void (*free_pgd_range)(struct mmu_gather *tlb, unsigned long addr,
+ unsigned long end, unsigned long floor,
+ unsigned long ceiling);
+ int (*init_module_vma)(struct vm_area_struct *vma,
+ struct vm_area_struct *old_vma);
+ void (*exit_module_vma)(struct vm_area_struct *vma);
+ int (*init_module_mm)(struct mm_struct *mm,
+ struct mm_module_struct *mm_mod);
+ int (*exit_module_mm)(struct mm_struct *mm,
+ struct mm_module_struct *mm_mod);
+};
+
+---------------------------------------------------------------
+Physical Memory Module Interface Points:
+
+Page release interception:
+ int (*put_page)(struct page *page);
+
+ Called by put_page() to allow a pmem_module to receive a released page
+ under it's management. Returns 1 if page was "taken" (determined to
+ belong to the pmem_module), or 0 if not.
+
+ int (*release_page)(struct page *page, struct zone **zonep,
+ unsigned long flags);
+
+ Called by release_pages() to allow a pmem_module to receive a released
+ page under it's management. Returns 1 if page was "taken" (determined to
+ belong to the pmem_module), or 0 if not. If page was taken, the spinlock
+ &(*zonep)->lru_lock must also be released as per similar behavior in
+ release_pages().
+
+Memory hotplug support:
+ int (*sparse_mem_map_populate)(unsigned long pnum, int nid);
+
+ Called by kmalloc_section_memmap() to allow the pmem_module to
+ initialize page mapping state associated with newly discovered
+ physical memory. Must return 0 if not successful.
+
+struct pmem_module_operations_struct {
+ int (*put_page)(struct page *page);
+ int (*release_page)(struct page *page, struct zone **zonep,
+ unsigned long flags);
+ int (*sparse_mem_map_populate)(unsigned long pnum, int nid);
+};
+
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index f627779..94ee45b 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -1122,16 +1122,26 @@
/*
* If for any reason at all we couldn't handle the fault,
* make sure we exit gracefully rather than endlessly redo
* the fault:
*/
fault = handle_mm_fault(mm, vma, address, flags);
if (unlikely(fault & VM_FAULT_ERROR)) {
+#ifdef CONFIG_MM_MODULES
+ if (fault & (VM_FAULT_SIGSEGV)) {
+ if (fault & VM_FAULT_SEGV_ACCERR)
+ bad_area_access_error(regs, error_code,
+ address);
+ else
+ bad_area(regs, error_code, address);
+ return;
+ }
+#endif /* CONFIG_MM_MODULES */
mm_fault_error(regs, error_code, address, fault);
return;
}
/*
* Major/minor page fault accounting is only done on the
* initial attempt. If we go through a retry, it is extremely
* likely that the page will be found in page cache at that point.
diff --git a/arch/x86/mm/gup.c b/arch/x86/mm/gup.c
index 738e659..f25621b 100644
--- a/arch/x86/mm/gup.c
+++ b/arch/x86/mm/gup.c
@@ -57,16 +57,30 @@
smp_rmb();
if (unlikely(pte.pte_low != ptep->pte_low))
goto retry;
return pte;
#endif
}
+#ifdef CONFIG_MM_MODULES
+static inline int get_page_not_zero(struct page *page)
+{
+ page = compound_head(page);
+ return atomic_inc_not_zero(&page->_count);
+}
+
+static inline int get_head_page_multiple_not_zero(struct page *page, int nr)
+{
+ VM_BUG_ON(page != compound_head(page));
+ return atomic_add_unless(&page->_count, nr, 0);
+}
+#endif /* CONFIG_MM_MODULES */
+
/*
* The performance critical leaf functions are made noinline otherwise gcc
* inlines everything into a single function which results in too much
* register pressure.
*/
static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
unsigned long end, int write, struct page **pages, int *nr)
{
@@ -83,17 +97,23 @@
struct page *page;
if ((pte_flags(pte) & (mask | _PAGE_SPECIAL)) != mask) {
pte_unmap(ptep);
return 0;
}
VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
page = pte_page(pte);
+#ifdef CONFIG_MM_MODULES
+ /* indicate failure if page ref count was already 0 */
+ if (!get_page_not_zero(page))
+ return 0;
+#else /* !CONFIG_MM_MODULES */
get_page(page);
+#endif /* CONFIG_MM_MODULES */
pages[*nr] = page;
(*nr)++;
} while (ptep++, addr += PAGE_SIZE, addr != end);
pte_unmap(ptep - 1);
return 1;
}
@@ -127,19 +147,28 @@
page = head + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
do {
VM_BUG_ON(compound_head(page) != head);
pages[*nr] = page;
(*nr)++;
page++;
refs++;
} while (addr += PAGE_SIZE, addr != end);
+#ifdef CONFIG_MM_MODULES
+ if (!get_head_page_multiple_not_zero(head, refs)) {
+ /* revert nr pages, indicate failure (ref count was 0) */
+ (*nr) -= refs;
+ return 0;
+ }
+ return 1;
+#else /* !CONFIG_MM_MODULES */
get_head_page_multiple(head, refs);
return 1;
+#endif /* CONFIG_MM_MODULES */
}
static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
int write, struct page **pages, int *nr)
{
unsigned long next;
pmd_t *pmdp;
@@ -184,19 +213,28 @@
page = head + ((addr & ~PUD_MASK) >> PAGE_SHIFT);
do {
VM_BUG_ON(compound_head(page) != head);
pages[*nr] = page;
(*nr)++;
page++;
refs++;
} while (addr += PAGE_SIZE, addr != end);
+#ifdef CONFIG_MM_MODULES
+ if (!get_head_page_multiple_not_zero(head, refs)) {
+ /* revert nr pages, indicate failure (ref count was 0) */
+ (*nr) -= refs;
+ return 0;
+ }
+ return 1;
+#else /* !CONFIG_MM_MODULES */
get_head_page_multiple(head, refs);
return 1;
+#endif /* CONFIG_MM_MODULES */
}
static int gup_pud_range(pgd_t pgd, unsigned long addr, unsigned long end,
int write, struct page **pages, int *nr)
{
unsigned long next;
pud_t *pudp;
diff --git a/drivers/misc/sgi-gru/grufault.c b/drivers/misc/sgi-gru/grufault.c
index 38657cd..31e0efe 100644
--- a/drivers/misc/sgi-gru/grufault.c
+++ b/drivers/misc/sgi-gru/grufault.c
@@ -187,16 +187,20 @@
* 1 - (atomic only) try again in non-atomic context
*/
static int non_atomic_pte_lookup(struct vm_area_struct *vma,
unsigned long vaddr, int write,
unsigned long *paddr, int *pageshift)
{
struct page *page;
+#ifdef CONFIG_MM_MODULES
+ if (vma->mm_module_ops)
+ return -EFAULT;
+#endif /* CONFIG_MM_MODULES */
#ifdef CONFIG_HUGETLB_PAGE
*pageshift = is_vm_hugetlb_page(vma) ? HPAGE_SHIFT : PAGE_SHIFT;
#else
*pageshift = PAGE_SHIFT;
#endif
if (get_user_pages
(current, current->mm, vaddr, 1, write, 0, &page, NULL) <= 0)
return -EFAULT;
@@ -246,16 +250,19 @@
return 1;
*paddr = pte_pfn(pte) << PAGE_SHIFT;
#ifdef CONFIG_HUGETLB_PAGE
*pageshift = is_vm_hugetlb_page(vma) ? HPAGE_SHIFT : PAGE_SHIFT;
#else
*pageshift = PAGE_SHIFT;
#endif
+#ifdef CONFIG_MM_MODULES
+ *pageshift = (pmd_large(*pmdp)) ? HPAGE_SHIFT : PAGE_SHIFT;
+#endif /* CONFIG_MM_MODULES */
return 0;
err:
return 1;
}
static int gru_vtop(struct gru_thread_state *gts, unsigned long vaddr,
int write, int atomic, unsigned long *gpa, int *pageshift)
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 535e763..4c11f2f 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -1910,16 +1910,43 @@
*/
segs = current->mm->map_count;
segs += elf_core_extra_phdrs();
gate_vma = get_gate_vma(current);
if (gate_vma != NULL)
segs++;
+#ifdef CONFIG_MM_MODULES
+ /* Find out how many extra regions (if any) there are in vmas: */
+ for (vma = first_vma(current, gate_vma); vma != NULL;
+ vma = next_vma(vma, gate_vma)) {
+ if (vma->mm_module_ops) {
+ int nr_regions = 0;
+ unsigned long range_start = vma->vm_start;
+ unsigned long range_end;
+ do {
+ BUG_ON(!vma->mm_module_ops->probe_mapped);
+ if (vma->mm_module_ops->probe_mapped(vma,
+ range_start,
+ &range_end, NULL) &&
+ vma_dump_size(vma, current->mm->flags) > 0)
+ nr_regions++;
+ } while (range_start = range_end, range_start <
+ vma->vm_end);
+ /*
+ * Aadjust segment count according to # of regions in
+ * vma. Note: this should decrement segment count for
+ * vmas with no mapped regions.
+ */
+ segs += nr_regions - 1;
+ }
+ }
+#endif /* CONFIG_MM_MODULES */
+
/* for notes section */
segs++;
/* If segs > PN_XNUM(0xffff), then e_phnum overflows. To avoid
* this, kernel supports extended numbering. Have a look at
* include/linux/elf.h for further information. */
e_phnum = segs > PN_XNUM ? PN_XNUM : segs;
@@ -1977,17 +2004,52 @@
if (size > cprm->limit
|| !dump_write(cprm->file, phdr4note, sizeof(*phdr4note)))
goto end_coredump;
/* Write program headers for segments dump */
for (vma = first_vma(current, gate_vma); vma != NULL;
vma = next_vma(vma, gate_vma)) {
struct elf_phdr phdr;
-
+#if CONFIG_MM_MODULES
+ unsigned long range_start = vma->vm_start;
+ unsigned long range_end = vma->vm_end;
+ unsigned long range_vm_flags = vma->vm_flags;
+ do {
+ if (vma->mm_module_ops) {
+ BUG_ON(!vma->mm_module_ops->probe_mapped);
+ if (!vma->mm_module_ops->
+ probe_mapped(vma, range_start, &range_end,
+ &range_vm_flags) ||
+ vma_dump_size(vma, cprm->mm_flags) == 0)
+ continue;
+ }
+
+ phdr.p_type = PT_LOAD;
+ phdr.p_offset = offset;
+ phdr.p_vaddr = range_start;
+ phdr.p_paddr = 0;
+ phdr.p_filesz = vma->mm_module_ops ?
+ (range_end - range_start) :
+ vma_dump_size(vma, cprm->mm_flags);
+ phdr.p_memsz = range_end - range_start;
+ offset += phdr.p_filesz;
+ phdr.p_flags = range_vm_flags & VM_READ ? PF_R : 0;
+ if (range_vm_flags & VM_WRITE)
+ phdr.p_flags |= PF_W;
+ if (range_vm_flags & VM_EXEC)
+ phdr.p_flags |= PF_X;
+ phdr.p_align = ELF_EXEC_PAGESIZE;
+
+ size += sizeof(phdr);
+ if (size > cprm->limit
+ || !dump_write(cprm->file, &phdr, sizeof(phdr)))
+ goto end_coredump;
+ } while (range_start = range_end, range_start < vma->vm_end);
+#else /* CONFIG_MM_MODULES */
phdr.p_type = PT_LOAD;
phdr.p_offset = offset;
phdr.p_vaddr = vma->vm_start;
phdr.p_paddr = 0;
phdr.p_filesz = vma_dump_size(vma, cprm->mm_flags);
phdr.p_memsz = vma->vm_end - vma->vm_start;
offset += phdr.p_filesz;
phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
@@ -1996,16 +2058,17 @@
if (vma->vm_flags & VM_EXEC)
phdr.p_flags |= PF_X;
phdr.p_align = ELF_EXEC_PAGESIZE;
size += sizeof(phdr);
if (size > cprm->limit
|| !dump_write(cprm->file, &phdr, sizeof(phdr)))
goto end_coredump;
+#endif /* CONFIG_MM_MODULES */
}
if (!elf_core_write_extra_phdrs(cprm->file, offset, &size, cprm->limit))
goto end_coredump;
/* write out the notes section */
if (!write_note_info(&info, cprm->file, &foffset))
goto end_coredump;
@@ -2017,16 +2080,53 @@
if (!dump_seek(cprm->file, dataoff - foffset))
goto end_coredump;
for (vma = first_vma(current, gate_vma); vma != NULL;
vma = next_vma(vma, gate_vma)) {
unsigned long addr;
unsigned long end;
+#ifdef CONFIG_MM_MODULES
+ unsigned long range_start = vma->vm_start;
+ unsigned long range_end;
+ end = (vma->mm_module_ops ? vma->vm_end :
+ vma->vm_start + vma_dump_size(vma, cprm->mm_flags));
+ range_end = end;
+
+ do {
+ if (vma->mm_module_ops) {
+ BUG_ON(!vma->mm_module_ops->probe_mapped);
+ if (!vma->mm_module_ops->
+ probe_mapped(vma, range_start, &range_end,
+ NULL) ||
+ vma_dump_size(vma, cprm->mm_flags) == 0)
+ continue;
+ }
+
+ for (addr = range_start; addr < range_end;
+ addr += PAGE_SIZE) {
+ struct page *page;
+ int stop;
+
+ page = get_dump_page(addr);
+ if (page) {
+ void *kaddr = kmap(page);
+ stop = ((size += PAGE_SIZE) > cprm->limit) ||
+ !dump_write(cprm->file, kaddr,
+ PAGE_SIZE);
+ kunmap(page);
+ page_cache_release(page);
+ } else
+ stop = !dump_seek(cprm->file, PAGE_SIZE);
+ if (stop)
+ goto end_coredump;
+ }
+ } while (range_start = range_end, range_start < end);
+#else /* CONFIG_MM_MODULES */
end = vma->vm_start + vma_dump_size(vma, cprm->mm_flags);
for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE) {
struct page *page;
int stop;
page = get_dump_page(addr);
if (page) {
@@ -2036,16 +2136,17 @@
PAGE_SIZE);
kunmap(page);
page_cache_release(page);
} else
stop = !dump_seek(cprm->file, PAGE_SIZE);
if (stop)
goto end_coredump;
}
+#endif /* CONFIG_MM_MODULES */
}
if (!elf_core_write_extra_data(cprm->file, &size, cprm->limit))
goto end_coredump;
if (e_phnum == PN_XNUM) {
size += sizeof(*shdr4extnum);
if (size > cprm->limit
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 47f5b14..3631572 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -222,25 +222,38 @@
}
/* We don't show the stack guard page in /proc/maps */
start = vma->vm_start;
if (vma->vm_flags & VM_GROWSDOWN)
if (!vma_stack_continue(vma->vm_prev, vma->vm_start))
start += PAGE_SIZE;
+#ifdef CONFIG_MM_MODULES
+ seq_printf(m, "%08lx-%08lx %c%c%c%c%c %08llx %02x:%02x %lu %n",
+ vma->vm_start,
+ vma->vm_end,
+ flags & VM_READ ? 'r' : '-',
+ flags & VM_WRITE ? 'w' : '-',
+ flags & VM_EXEC ? 'x' : '-',
+ flags & VM_MAYSHARE ? 's' : 'p',
+ vma->mm_module_ops ? 'm' : '\0',
+ ((loff_t)vma->vm_pgoff) << PAGE_SHIFT,
+ MAJOR(dev), MINOR(dev), ino, &len);
+#else /* CONFIG_MM_MODULES */
seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n",
start,
vma->vm_end,
flags & VM_READ ? 'r' : '-',
flags & VM_WRITE ? 'w' : '-',
flags & VM_EXEC ? 'x' : '-',
flags & VM_MAYSHARE ? 's' : 'p',
pgoff,
MAJOR(dev), MINOR(dev), ino, &len);
+#endif /* CONFIG_MM_MODULES */
/*
* Print the dentry name for named mappings, and a
* special [heap] marker for the heap:
*/
if (file) {
pad_len_spaces(m, len);
seq_path(m, &file->f_path, "\n");
@@ -395,16 +408,19 @@
.pmd_entry = smaps_pte_range,
.mm = vma->vm_mm,
.private = &mss,
};
memset(&mss, 0, sizeof mss);
mss.vma = vma;
/* mmap_sem is held in m_start */
+#ifdef CONFIG_MM_MODULES
+ if (!vma->mm_module_ops)
+#endif /* CONFIG_MM_MODULES */
if (vma->vm_mm && !is_vm_hugetlb_page(vma))
walk_page_range(vma->vm_start, vma->vm_end, &smaps_walk);
show_map_vma(m, vma);
seq_printf(m,
"Size: %8lu kB\n"
"Rss: %8lu kB\n"
@@ -511,16 +527,19 @@
if (mm) {
struct mm_walk clear_refs_walk = {
.pmd_entry = clear_refs_pte_range,
.mm = mm,
};
down_read(&mm->mmap_sem);
for (vma = mm->mmap; vma; vma = vma->vm_next) {
clear_refs_walk.private = vma;
+#ifdef CONFIG_MM_MODULES
+ if (!vma->mm_module_ops)
+#endif /* CONFIG_MM_MODULES */
if (is_vm_hugetlb_page(vma))
continue;
/*
* Writing 1 to /proc/pid/clear_refs affects all pages.
*
* Writing 2 to /proc/pid/clear_refs only affects
* Anonymous pages.
*
@@ -627,16 +646,19 @@
/* check to see if we've left 'vma' behind
* and need a new, higher one */
if (vma && (addr >= vma->vm_end))
vma = find_vma(walk->mm, addr);
/* check that 'vma' actually covers this address,
* and that it isn't a huge page vma */
if (vma && (vma->vm_start <= addr) &&
+#ifdef CONFIG_MM_MODULES
+ !vma->mm_module_ops &&
+#endif /* CONFIG_MM_MODULES */
!is_vm_hugetlb_page(vma)) {
pte = pte_offset_map(pmd, addr);
pfn = pte_to_pagemap_entry(*pte);
/* unmap before userspace copy */
pte_unmap(pte);
}
err = add_to_pagemap(addr, pfn, pm);
if (err)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 462acaf..6f3e1dc 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -229,25 +229,93 @@
int (*migrate)(struct vm_area_struct *vma, const nodemask_t *from,
const nodemask_t *to, unsigned long flags);
#endif
};
struct mmu_gather;
struct inode;
+#ifdef CONFIG_PMEM_MODULES
+struct pmem_module_operations_struct {
+ int (*put_page)(struct page *page);
+ int (*get_page)(struct page *page);
+ int (*sparse_mem_map_populate)(unsigned long pnum, int nid);
+};
+#endif /* CONFIG_PMEM_MODULES */
+
+#ifdef CONFIG_MM_MODULES
+struct zap_details;
+
+struct mm_module_operations_struct {
+ int (*handle_mm_fault)(struct mm_struct *mm,
+ struct vm_area_struct *vma, unsigned long addr,
+ unsigned int flags);
+ int (*change_protection)(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end, unsigned long newflags);
+ int (*copy_page_range)(struct mm_struct *dst_mm,
+ struct mm_struct *src_mm, struct vm_area_struct *vma);
+ int (*follow_page)(struct mm_struct *mm, struct vm_area_struct *vma,
+ struct page **pages, struct vm_area_struct **vmas,
+ unsigned long *position, int *length,
+ int i, int write);
+ int (*probe_mapped)(struct vm_area_struct *vma, unsigned long start,
+ unsigned long *end_range, unsigned long *range_vm_flags);
+ unsigned long (*unmap_page_range)(struct mmu_gather **tlbp,
+ struct vm_area_struct *vma, unsigned long addr,
+ unsigned long end, long *zap_work,
+ struct zap_details *details);
+ void (*free_pgd_range)(struct mmu_gather *tlb, unsigned long addr,
+ unsigned long end, unsigned long floor,
+ unsigned long ceiling);
+ int (*init_module_vma)(struct vm_area_struct *vma,
+ struct vm_area_struct *old_vma);
+ void (*exit_module_vma)(struct vm_area_struct *vma);
+ int (*init_module_mm)(struct mm_struct *mm,
+ struct mm_module_struct *mm_mod);
+ int (*exit_module_mm)(struct mm_struct *mm,
+ struct mm_module_struct *mm_mod);
+};
+#endif /* CONFIG_MM_MODULES */
+
#define page_private(page) ((page)->private)
#define set_page_private(page, v) ((page)->private = (v))
/*
* FIXME: take this include out, include page-flags.h in
* files which need it (119 of them)
*/
#include <linux/page-flags.h>
+#ifdef CONFIG_PMEM_MODULES
+static inline void pmem_modules_get_page(struct page *page)
+{
+ struct pmem_module_struct *module = pmem_modules;
+ for (module = pmem_modules; module; module = module->next) {
+ VM_BUG_ON(!module->pmem_module_ops->get_page);
+ if (module->pmem_module_ops->get_page(page))
+ return;
+ }
+ /* One of the modules should have picked the page up */
+ BUG();
+}
+
+static inline void pmem_modules_put_page(struct page *page)
+{
+ struct pmem_module_struct *module = pmem_modules;
+ for (module = pmem_modules; module; module = module->next) {
+ VM_BUG_ON(!module->pmem_module_ops->put_page);
+ if (module->pmem_module_ops->put_page(page))
+ return;
+ }
+ /* One of the modules should have picked the page up */
+ BUG();
+}
+#endif /* CONFIG_PMEM_MODULES */
+
/*
* Methods to modify the page usage count.
*
* What counts for a page usage:
* - cache mapping (page->mapping)
* - private data (page->private)
* - page mapped in a task's page tables, each mapping
* is counted separately
@@ -314,16 +382,22 @@
static inline int page_count(struct page *page)
{
return atomic_read(&compound_head(page)->_count);
}
static inline void get_page(struct page *page)
{
+#ifdef CONFIG_PMEM_MODULES
+ if (unlikely(PagePmemModule(page))) {
+ pmem_modules_get_page(page);
+ return;
+ }
+#endif /* CONFIG_PMEM_MODULES */
page = compound_head(page);
VM_BUG_ON(atomic_read(&page->_count) == 0);
atomic_inc(&page->_count);
}
static inline struct page *virt_to_head_page(const void *x)
{
struct page *page = virt_to_page(x);
@@ -723,18 +797,27 @@
#define VM_FAULT_HWPOISON_LARGE 0x0020 /* Hit poisoned large page. Index encoded in upper bits */
#define VM_FAULT_NOPAGE 0x0100 /* ->fault installed the pte, not return page */
#define VM_FAULT_LOCKED 0x0200 /* ->fault locked the returned page */
#define VM_FAULT_RETRY 0x0400 /* ->fault blocked, must retry */
#define VM_FAULT_HWPOISON_LARGE_MASK 0xf000 /* encodes hpage index for large hwpoison */
+#ifdef CONFIG_MM_MODULES
+#define VM_FAULT_SEGV_ACCERR 0x1000
+#define VM_FAULT_SEGV_MAPERR 0x2000
+#define VM_FAULT_SIGSEGV (VM_FAULT_SEGV_ACCERR | VM_FAULT_SEGV_MAPERR)
+#define VM_FAULT_ERROR \
+ (VM_FAULT_OOM | VM_FAULT_SIGBUS | VM_FAULT_HWPOISON | \
+ VM_FAULT_HWPOISON_LARGE | VM_FAULT_SIGSEGV)
+#else /* !CONFIG_MM_MODULES */
#define VM_FAULT_ERROR (VM_FAULT_OOM | VM_FAULT_SIGBUS | VM_FAULT_HWPOISON | \
VM_FAULT_HWPOISON_LARGE)
+#endif /* CONFIG_MM_MODULES */
/* Encode hstate index for a hwpoisoned large page */
#define VM_FAULT_SET_HINDEX(x) ((x) << 12)
#define VM_FAULT_GET_HINDEX(x) (((x) >> 12) & 0xf)
/*
* Can be called by the pagefault handler when it gets a VM_FAULT_OOM.
*/
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index b8bb9a6..0dc8c1a 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -178,16 +178,20 @@
unsigned long vm_truncate_count;/* truncate_count or restart_addr */
#ifndef CONFIG_MMU
struct vm_region *vm_region; /* NOMMU mapping region */
#endif
#ifdef CONFIG_NUMA
struct mempolicy *vm_policy; /* NUMA policy for the VMA */
#endif
+#ifdef CONFIG_MM_MODULES
+ struct mm_module_operations_struct * mm_module_ops;
+ void * mm_module_vma_state;
+#endif /* CONFIG_MM_MODULES */
};
struct core_thread {
struct task_struct *task;
struct core_thread *next;
};
struct core_state {
@@ -214,16 +218,33 @@
int count[NR_MM_COUNTERS];
};
#else /* !USE_SPLIT_PTLOCKS */
struct mm_rss_stat {
unsigned long count[NR_MM_COUNTERS];
};
#endif /* !USE_SPLIT_PTLOCKS */
+#ifdef CONFIG_PMEM_MODULES
+struct pmem_module_struct {
+ struct pmem_module_operations_struct * pmem_module_ops;
+ struct pmem_module_struct *next;
+};
+
+extern struct pmem_module_struct *pmem_modules;
+#endif /* CONFIG_PMEM_MODULES */
+
+#ifdef CONFIG_MM_MODULES
+struct mm_module_struct {
+ struct mm_module_operations_struct * mm_module_ops;
+ void * mm_module_mm_state;
+ struct mm_module_struct *next;
+};
+#endif /* CONFIG_MM_MODULES */
+
struct mm_struct {
struct vm_area_struct * mmap; /* list of VMAs */
struct rb_root mm_rb;
struct vm_area_struct * mmap_cache; /* last find_vma result */
#ifdef CONFIG_MMU
unsigned long (*get_unmapped_area) (struct file *filp,
unsigned long addr, unsigned long len,
unsigned long pgoff, unsigned long flags);
@@ -305,16 +326,19 @@
#ifdef CONFIG_PROC_FS
/* store ref to file /proc/<pid>/exe symlink points to */
struct file *exe_file;
unsigned long num_exe_file_vmas;
#endif
#ifdef CONFIG_MMU_NOTIFIER
struct mmu_notifier_mm *mmu_notifier_mm;
#endif
+#ifdef CONFIG_MM_MODULES
+ struct mm_module_struct *mm_modules;
+#endif /* CONFIG_MM_MODULES */
/* How many tasks sharing this mm are OOM_DISABLE */
atomic_t oom_disable_count;