diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-12-14 23:12:43 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-12-14 23:12:43 -0500 |
commit | 4d98ead183a2be77bfea425d5243e32629eaaeb1 (patch) | |
tree | abd2282b8fed47a972a0334fb5b466d640fe385e | |
parent | a57cb1c1d7974c62a5c80f7869e35b492ace12cd (diff) | |
parent | 4d217a5adccf5e806790c37c61cc374a08bd7381 (diff) |
Merge tag 'modules-for-v4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/jeyu/linux
Pull modules updates from Jessica Yu:
"Summary of modules changes for the 4.10 merge window:
- The rodata= cmdline parameter has been extended to additionally
apply to module mappings
- Fix a hard to hit race between module loader error/clean up
handling and ftrace registration
- Some code cleanups, notably panic.c and modules code use a unified
taint_flags table now. This is much cleaner than duplicating the
taint flag code in modules.c"
* tag 'modules-for-v4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/jeyu/linux:
module: fix DEBUG_SET_MODULE_RONX typo
module: extend 'rodata=off' boot cmdline parameter to module mappings
module: Fix a comment above strong_try_module_get()
module: When modifying a module's text ignore modules which are going away too
module: Ensure a module's state is set accordingly during module coming cleanup code
module: remove trailing whitespace
taint/module: Clean up global and module taint flags handling
modpost: free allocated memory
-rw-r--r-- | include/linux/init.h | 3 | ||||
-rw-r--r-- | include/linux/kernel.h | 9 | ||||
-rw-r--r-- | include/linux/module.h | 4 | ||||
-rw-r--r-- | init/main.c | 7 | ||||
-rw-r--r-- | kernel/module.c | 69 | ||||
-rw-r--r-- | kernel/panic.c | 53 | ||||
-rw-r--r-- | scripts/mod/modpost.c | 2 |
7 files changed, 89 insertions, 58 deletions
diff --git a/include/linux/init.h b/include/linux/init.h index e30104ceb86d..885c3e6d0f9d 100644 --- a/include/linux/init.h +++ b/include/linux/init.h | |||
@@ -126,6 +126,9 @@ void prepare_namespace(void); | |||
126 | void __init load_default_modules(void); | 126 | void __init load_default_modules(void); |
127 | int __init init_rootfs(void); | 127 | int __init init_rootfs(void); |
128 | 128 | ||
129 | #if defined(CONFIG_DEBUG_RODATA) || defined(CONFIG_DEBUG_SET_MODULE_RONX) | ||
130 | extern bool rodata_enabled; | ||
131 | #endif | ||
129 | #ifdef CONFIG_DEBUG_RODATA | 132 | #ifdef CONFIG_DEBUG_RODATA |
130 | void mark_rodata_ro(void); | 133 | void mark_rodata_ro(void); |
131 | #endif | 134 | #endif |
diff --git a/include/linux/kernel.h b/include/linux/kernel.h index d234cd31e75a..56aec84237ad 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h | |||
@@ -511,6 +511,15 @@ extern enum system_states { | |||
511 | #define TAINT_UNSIGNED_MODULE 13 | 511 | #define TAINT_UNSIGNED_MODULE 13 |
512 | #define TAINT_SOFTLOCKUP 14 | 512 | #define TAINT_SOFTLOCKUP 14 |
513 | #define TAINT_LIVEPATCH 15 | 513 | #define TAINT_LIVEPATCH 15 |
514 | #define TAINT_FLAGS_COUNT 16 | ||
515 | |||
516 | struct taint_flag { | ||
517 | char true; /* character printed when tainted */ | ||
518 | char false; /* character printed when not tainted */ | ||
519 | bool module; /* also show as a per-module taint flag */ | ||
520 | }; | ||
521 | |||
522 | extern const struct taint_flag taint_flags[TAINT_FLAGS_COUNT]; | ||
514 | 523 | ||
515 | extern const char hex_asc[]; | 524 | extern const char hex_asc[]; |
516 | #define hex_asc_lo(x) hex_asc[((x) & 0x0f)] | 525 | #define hex_asc_lo(x) hex_asc[((x) & 0x0f)] |
diff --git a/include/linux/module.h b/include/linux/module.h index 0c3207d26ac0..7c84273d60b9 100644 --- a/include/linux/module.h +++ b/include/linux/module.h | |||
@@ -399,7 +399,7 @@ struct module { | |||
399 | /* Arch-specific module values */ | 399 | /* Arch-specific module values */ |
400 | struct mod_arch_specific arch; | 400 | struct mod_arch_specific arch; |
401 | 401 | ||
402 | unsigned int taints; /* same bits as kernel:tainted */ | 402 | unsigned long taints; /* same bits as kernel:taint_flags */ |
403 | 403 | ||
404 | #ifdef CONFIG_GENERIC_BUG | 404 | #ifdef CONFIG_GENERIC_BUG |
405 | /* Support for BUG */ | 405 | /* Support for BUG */ |
@@ -412,7 +412,7 @@ struct module { | |||
412 | /* Protected by RCU and/or module_mutex: use rcu_dereference() */ | 412 | /* Protected by RCU and/or module_mutex: use rcu_dereference() */ |
413 | struct mod_kallsyms *kallsyms; | 413 | struct mod_kallsyms *kallsyms; |
414 | struct mod_kallsyms core_kallsyms; | 414 | struct mod_kallsyms core_kallsyms; |
415 | 415 | ||
416 | /* Section attributes */ | 416 | /* Section attributes */ |
417 | struct module_sect_attrs *sect_attrs; | 417 | struct module_sect_attrs *sect_attrs; |
418 | 418 | ||
diff --git a/init/main.c b/init/main.c index 23c275cca73a..c81c9fa21bc7 100644 --- a/init/main.c +++ b/init/main.c | |||
@@ -81,6 +81,7 @@ | |||
81 | #include <linux/integrity.h> | 81 | #include <linux/integrity.h> |
82 | #include <linux/proc_ns.h> | 82 | #include <linux/proc_ns.h> |
83 | #include <linux/io.h> | 83 | #include <linux/io.h> |
84 | #include <linux/cache.h> | ||
84 | 85 | ||
85 | #include <asm/io.h> | 86 | #include <asm/io.h> |
86 | #include <asm/bugs.h> | 87 | #include <asm/bugs.h> |
@@ -925,14 +926,16 @@ static int try_to_run_init_process(const char *init_filename) | |||
925 | 926 | ||
926 | static noinline void __init kernel_init_freeable(void); | 927 | static noinline void __init kernel_init_freeable(void); |
927 | 928 | ||
928 | #ifdef CONFIG_DEBUG_RODATA | 929 | #if defined(CONFIG_DEBUG_RODATA) || defined(CONFIG_DEBUG_SET_MODULE_RONX) |
929 | static bool rodata_enabled = true; | 930 | bool rodata_enabled __ro_after_init = true; |
930 | static int __init set_debug_rodata(char *str) | 931 | static int __init set_debug_rodata(char *str) |
931 | { | 932 | { |
932 | return strtobool(str, &rodata_enabled); | 933 | return strtobool(str, &rodata_enabled); |
933 | } | 934 | } |
934 | __setup("rodata=", set_debug_rodata); | 935 | __setup("rodata=", set_debug_rodata); |
936 | #endif | ||
935 | 937 | ||
938 | #ifdef CONFIG_DEBUG_RODATA | ||
936 | static void mark_readonly(void) | 939 | static void mark_readonly(void) |
937 | { | 940 | { |
938 | if (rodata_enabled) | 941 | if (rodata_enabled) |
diff --git a/kernel/module.c b/kernel/module.c index 0e54d5bf0097..f7482db0f843 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -313,8 +313,11 @@ struct load_info { | |||
313 | } index; | 313 | } index; |
314 | }; | 314 | }; |
315 | 315 | ||
316 | /* We require a truly strong try_module_get(): 0 means failure due to | 316 | /* |
317 | ongoing or failed initialization etc. */ | 317 | * We require a truly strong try_module_get(): 0 means success. |
318 | * Otherwise an error is returned due to ongoing or failed | ||
319 | * initialization etc. | ||
320 | */ | ||
318 | static inline int strong_try_module_get(struct module *mod) | 321 | static inline int strong_try_module_get(struct module *mod) |
319 | { | 322 | { |
320 | BUG_ON(mod && mod->state == MODULE_STATE_UNFORMED); | 323 | BUG_ON(mod && mod->state == MODULE_STATE_UNFORMED); |
@@ -330,7 +333,7 @@ static inline void add_taint_module(struct module *mod, unsigned flag, | |||
330 | enum lockdep_ok lockdep_ok) | 333 | enum lockdep_ok lockdep_ok) |
331 | { | 334 | { |
332 | add_taint(flag, lockdep_ok); | 335 | add_taint(flag, lockdep_ok); |
333 | mod->taints |= (1U << flag); | 336 | set_bit(flag, &mod->taints); |
334 | } | 337 | } |
335 | 338 | ||
336 | /* | 339 | /* |
@@ -1138,24 +1141,13 @@ static inline int module_unload_init(struct module *mod) | |||
1138 | static size_t module_flags_taint(struct module *mod, char *buf) | 1141 | static size_t module_flags_taint(struct module *mod, char *buf) |
1139 | { | 1142 | { |
1140 | size_t l = 0; | 1143 | size_t l = 0; |
1144 | int i; | ||
1145 | |||
1146 | for (i = 0; i < TAINT_FLAGS_COUNT; i++) { | ||
1147 | if (taint_flags[i].module && test_bit(i, &mod->taints)) | ||
1148 | buf[l++] = taint_flags[i].true; | ||
1149 | } | ||
1141 | 1150 | ||
1142 | if (mod->taints & (1 << TAINT_PROPRIETARY_MODULE)) | ||
1143 | buf[l++] = 'P'; | ||
1144 | if (mod->taints & (1 << TAINT_OOT_MODULE)) | ||
1145 | buf[l++] = 'O'; | ||
1146 | if (mod->taints & (1 << TAINT_FORCED_MODULE)) | ||
1147 | buf[l++] = 'F'; | ||
1148 | if (mod->taints & (1 << TAINT_CRAP)) | ||
1149 | buf[l++] = 'C'; | ||
1150 | if (mod->taints & (1 << TAINT_UNSIGNED_MODULE)) | ||
1151 | buf[l++] = 'E'; | ||
1152 | if (mod->taints & (1 << TAINT_LIVEPATCH)) | ||
1153 | buf[l++] = 'K'; | ||
1154 | /* | ||
1155 | * TAINT_FORCED_RMMOD: could be added. | ||
1156 | * TAINT_CPU_OUT_OF_SPEC, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't | ||
1157 | * apply to modules. | ||
1158 | */ | ||
1159 | return l; | 1151 | return l; |
1160 | } | 1152 | } |
1161 | 1153 | ||
@@ -1911,6 +1903,9 @@ static void frob_writable_data(const struct module_layout *layout, | |||
1911 | /* livepatching wants to disable read-only so it can frob module. */ | 1903 | /* livepatching wants to disable read-only so it can frob module. */ |
1912 | void module_disable_ro(const struct module *mod) | 1904 | void module_disable_ro(const struct module *mod) |
1913 | { | 1905 | { |
1906 | if (!rodata_enabled) | ||
1907 | return; | ||
1908 | |||
1914 | frob_text(&mod->core_layout, set_memory_rw); | 1909 | frob_text(&mod->core_layout, set_memory_rw); |
1915 | frob_rodata(&mod->core_layout, set_memory_rw); | 1910 | frob_rodata(&mod->core_layout, set_memory_rw); |
1916 | frob_ro_after_init(&mod->core_layout, set_memory_rw); | 1911 | frob_ro_after_init(&mod->core_layout, set_memory_rw); |
@@ -1920,6 +1915,9 @@ void module_disable_ro(const struct module *mod) | |||
1920 | 1915 | ||
1921 | void module_enable_ro(const struct module *mod, bool after_init) | 1916 | void module_enable_ro(const struct module *mod, bool after_init) |
1922 | { | 1917 | { |
1918 | if (!rodata_enabled) | ||
1919 | return; | ||
1920 | |||
1923 | frob_text(&mod->core_layout, set_memory_ro); | 1921 | frob_text(&mod->core_layout, set_memory_ro); |
1924 | frob_rodata(&mod->core_layout, set_memory_ro); | 1922 | frob_rodata(&mod->core_layout, set_memory_ro); |
1925 | frob_text(&mod->init_layout, set_memory_ro); | 1923 | frob_text(&mod->init_layout, set_memory_ro); |
@@ -1952,6 +1950,9 @@ void set_all_modules_text_rw(void) | |||
1952 | { | 1950 | { |
1953 | struct module *mod; | 1951 | struct module *mod; |
1954 | 1952 | ||
1953 | if (!rodata_enabled) | ||
1954 | return; | ||
1955 | |||
1955 | mutex_lock(&module_mutex); | 1956 | mutex_lock(&module_mutex); |
1956 | list_for_each_entry_rcu(mod, &modules, list) { | 1957 | list_for_each_entry_rcu(mod, &modules, list) { |
1957 | if (mod->state == MODULE_STATE_UNFORMED) | 1958 | if (mod->state == MODULE_STATE_UNFORMED) |
@@ -1968,9 +1969,18 @@ void set_all_modules_text_ro(void) | |||
1968 | { | 1969 | { |
1969 | struct module *mod; | 1970 | struct module *mod; |
1970 | 1971 | ||
1972 | if (!rodata_enabled) | ||
1973 | return; | ||
1974 | |||
1971 | mutex_lock(&module_mutex); | 1975 | mutex_lock(&module_mutex); |
1972 | list_for_each_entry_rcu(mod, &modules, list) { | 1976 | list_for_each_entry_rcu(mod, &modules, list) { |
1973 | if (mod->state == MODULE_STATE_UNFORMED) | 1977 | /* |
1978 | * Ignore going modules since it's possible that ro | ||
1979 | * protection has already been disabled, otherwise we'll | ||
1980 | * run into protection faults at module deallocation. | ||
1981 | */ | ||
1982 | if (mod->state == MODULE_STATE_UNFORMED || | ||
1983 | mod->state == MODULE_STATE_GOING) | ||
1974 | continue; | 1984 | continue; |
1975 | 1985 | ||
1976 | frob_text(&mod->core_layout, set_memory_ro); | 1986 | frob_text(&mod->core_layout, set_memory_ro); |
@@ -1981,10 +1991,12 @@ void set_all_modules_text_ro(void) | |||
1981 | 1991 | ||
1982 | static void disable_ro_nx(const struct module_layout *layout) | 1992 | static void disable_ro_nx(const struct module_layout *layout) |
1983 | { | 1993 | { |
1984 | frob_text(layout, set_memory_rw); | 1994 | if (rodata_enabled) { |
1985 | frob_rodata(layout, set_memory_rw); | 1995 | frob_text(layout, set_memory_rw); |
1996 | frob_rodata(layout, set_memory_rw); | ||
1997 | frob_ro_after_init(layout, set_memory_rw); | ||
1998 | } | ||
1986 | frob_rodata(layout, set_memory_x); | 1999 | frob_rodata(layout, set_memory_x); |
1987 | frob_ro_after_init(layout, set_memory_rw); | ||
1988 | frob_ro_after_init(layout, set_memory_x); | 2000 | frob_ro_after_init(layout, set_memory_x); |
1989 | frob_writable_data(layout, set_memory_x); | 2001 | frob_writable_data(layout, set_memory_x); |
1990 | } | 2002 | } |
@@ -3709,6 +3721,7 @@ static int load_module(struct load_info *info, const char __user *uargs, | |||
3709 | sysfs_cleanup: | 3721 | sysfs_cleanup: |
3710 | mod_sysfs_teardown(mod); | 3722 | mod_sysfs_teardown(mod); |
3711 | coming_cleanup: | 3723 | coming_cleanup: |
3724 | mod->state = MODULE_STATE_GOING; | ||
3712 | blocking_notifier_call_chain(&module_notify_list, | 3725 | blocking_notifier_call_chain(&module_notify_list, |
3713 | MODULE_STATE_GOING, mod); | 3726 | MODULE_STATE_GOING, mod); |
3714 | klp_module_going(mod); | 3727 | klp_module_going(mod); |
@@ -4042,6 +4055,10 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, | |||
4042 | } | 4055 | } |
4043 | #endif /* CONFIG_KALLSYMS */ | 4056 | #endif /* CONFIG_KALLSYMS */ |
4044 | 4057 | ||
4058 | /* Maximum number of characters written by module_flags() */ | ||
4059 | #define MODULE_FLAGS_BUF_SIZE (TAINT_FLAGS_COUNT + 4) | ||
4060 | |||
4061 | /* Keep in sync with MODULE_FLAGS_BUF_SIZE !!! */ | ||
4045 | static char *module_flags(struct module *mod, char *buf) | 4062 | static char *module_flags(struct module *mod, char *buf) |
4046 | { | 4063 | { |
4047 | int bx = 0; | 4064 | int bx = 0; |
@@ -4086,7 +4103,7 @@ static void m_stop(struct seq_file *m, void *p) | |||
4086 | static int m_show(struct seq_file *m, void *p) | 4103 | static int m_show(struct seq_file *m, void *p) |
4087 | { | 4104 | { |
4088 | struct module *mod = list_entry(p, struct module, list); | 4105 | struct module *mod = list_entry(p, struct module, list); |
4089 | char buf[8]; | 4106 | char buf[MODULE_FLAGS_BUF_SIZE]; |
4090 | 4107 | ||
4091 | /* We always ignore unformed modules. */ | 4108 | /* We always ignore unformed modules. */ |
4092 | if (mod->state == MODULE_STATE_UNFORMED) | 4109 | if (mod->state == MODULE_STATE_UNFORMED) |
@@ -4257,7 +4274,7 @@ EXPORT_SYMBOL_GPL(__module_text_address); | |||
4257 | void print_modules(void) | 4274 | void print_modules(void) |
4258 | { | 4275 | { |
4259 | struct module *mod; | 4276 | struct module *mod; |
4260 | char buf[8]; | 4277 | char buf[MODULE_FLAGS_BUF_SIZE]; |
4261 | 4278 | ||
4262 | printk(KERN_DEFAULT "Modules linked in:"); | 4279 | printk(KERN_DEFAULT "Modules linked in:"); |
4263 | /* Most callers should already have preempt disabled, but make sure */ | 4280 | /* Most callers should already have preempt disabled, but make sure */ |
diff --git a/kernel/panic.c b/kernel/panic.c index e6480e20379e..c51edaa04fce 100644 --- a/kernel/panic.c +++ b/kernel/panic.c | |||
@@ -298,30 +298,27 @@ void panic(const char *fmt, ...) | |||
298 | 298 | ||
299 | EXPORT_SYMBOL(panic); | 299 | EXPORT_SYMBOL(panic); |
300 | 300 | ||
301 | 301 | /* | |
302 | struct tnt { | 302 | * TAINT_FORCED_RMMOD could be a per-module flag but the module |
303 | u8 bit; | 303 | * is being removed anyway. |
304 | char true; | 304 | */ |
305 | char false; | 305 | const struct taint_flag taint_flags[TAINT_FLAGS_COUNT] = { |
306 | }; | 306 | { 'P', 'G', true }, /* TAINT_PROPRIETARY_MODULE */ |
307 | 307 | { 'F', ' ', true }, /* TAINT_FORCED_MODULE */ | |
308 | static const struct tnt tnts[] = { | 308 | { 'S', ' ', false }, /* TAINT_CPU_OUT_OF_SPEC */ |
309 | { TAINT_PROPRIETARY_MODULE, 'P', 'G' }, | 309 | { 'R', ' ', false }, /* TAINT_FORCED_RMMOD */ |
310 | { TAINT_FORCED_MODULE, 'F', ' ' }, | 310 | { 'M', ' ', false }, /* TAINT_MACHINE_CHECK */ |
311 | { TAINT_CPU_OUT_OF_SPEC, 'S', ' ' }, | 311 | { 'B', ' ', false }, /* TAINT_BAD_PAGE */ |
312 | { TAINT_FORCED_RMMOD, 'R', ' ' }, | 312 | { 'U', ' ', false }, /* TAINT_USER */ |
313 | { TAINT_MACHINE_CHECK, 'M', ' ' }, | 313 | { 'D', ' ', false }, /* TAINT_DIE */ |
314 | { TAINT_BAD_PAGE, 'B', ' ' }, | 314 | { 'A', ' ', false }, /* TAINT_OVERRIDDEN_ACPI_TABLE */ |
315 | { TAINT_USER, 'U', ' ' }, | 315 | { 'W', ' ', false }, /* TAINT_WARN */ |
316 | { TAINT_DIE, 'D', ' ' }, | 316 | { 'C', ' ', true }, /* TAINT_CRAP */ |
317 | { TAINT_OVERRIDDEN_ACPI_TABLE, 'A', ' ' }, | 317 | { 'I', ' ', false }, /* TAINT_FIRMWARE_WORKAROUND */ |
318 | { TAINT_WARN, 'W', ' ' }, | 318 | { 'O', ' ', true }, /* TAINT_OOT_MODULE */ |
319 | { TAINT_CRAP, 'C', ' ' }, | 319 | { 'E', ' ', true }, /* TAINT_UNSIGNED_MODULE */ |
320 | { TAINT_FIRMWARE_WORKAROUND, 'I', ' ' }, | 320 | { 'L', ' ', false }, /* TAINT_SOFTLOCKUP */ |
321 | { TAINT_OOT_MODULE, 'O', ' ' }, | 321 | { 'K', ' ', true }, /* TAINT_LIVEPATCH */ |
322 | { TAINT_UNSIGNED_MODULE, 'E', ' ' }, | ||
323 | { TAINT_SOFTLOCKUP, 'L', ' ' }, | ||
324 | { TAINT_LIVEPATCH, 'K', ' ' }, | ||
325 | }; | 322 | }; |
326 | 323 | ||
327 | /** | 324 | /** |
@@ -348,16 +345,16 @@ static const struct tnt tnts[] = { | |||
348 | */ | 345 | */ |
349 | const char *print_tainted(void) | 346 | const char *print_tainted(void) |
350 | { | 347 | { |
351 | static char buf[ARRAY_SIZE(tnts) + sizeof("Tainted: ")]; | 348 | static char buf[TAINT_FLAGS_COUNT + sizeof("Tainted: ")]; |
352 | 349 | ||
353 | if (tainted_mask) { | 350 | if (tainted_mask) { |
354 | char *s; | 351 | char *s; |
355 | int i; | 352 | int i; |
356 | 353 | ||
357 | s = buf + sprintf(buf, "Tainted: "); | 354 | s = buf + sprintf(buf, "Tainted: "); |
358 | for (i = 0; i < ARRAY_SIZE(tnts); i++) { | 355 | for (i = 0; i < TAINT_FLAGS_COUNT; i++) { |
359 | const struct tnt *t = &tnts[i]; | 356 | const struct taint_flag *t = &taint_flags[i]; |
360 | *s++ = test_bit(t->bit, &tainted_mask) ? | 357 | *s++ = test_bit(i, &tainted_mask) ? |
361 | t->true : t->false; | 358 | t->true : t->false; |
362 | } | 359 | } |
363 | *s = 0; | 360 | *s = 0; |
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index bd8349759095..5a6b39a29b7a 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c | |||
@@ -2371,6 +2371,7 @@ static void write_dump(const char *fname) | |||
2371 | } | 2371 | } |
2372 | } | 2372 | } |
2373 | write_if_changed(&buf, fname); | 2373 | write_if_changed(&buf, fname); |
2374 | free(buf.p); | ||
2374 | } | 2375 | } |
2375 | 2376 | ||
2376 | struct ext_sym_list { | 2377 | struct ext_sym_list { |
@@ -2496,6 +2497,7 @@ int main(int argc, char **argv) | |||
2496 | "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n"); | 2497 | "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n"); |
2497 | } | 2498 | } |
2498 | } | 2499 | } |
2500 | free(buf.p); | ||
2499 | 2501 | ||
2500 | return err; | 2502 | return err; |
2501 | } | 2503 | } |