Commit 9e319251 authored by Linus Torvalds's avatar Linus Torvalds

Merge penguin:v2.5/linux

into home.transmeta.com:/home/torvalds/v2.5/linux
parents 40aafff3 d1791d31
...@@ -1068,6 +1068,8 @@ The pdflush writeback daemons will periodically wake up and write `old' data ...@@ -1068,6 +1068,8 @@ The pdflush writeback daemons will periodically wake up and write `old' data
out to disk. This tunable expresses the interval between those wakeups, in out to disk. This tunable expresses the interval between those wakeups, in
100'ths of a second. 100'ths of a second.
Setting this to zero disables periodic writeback altogether.
dirty_expire_centisecs dirty_expire_centisecs
---------------------- ----------------------
......
...@@ -18,7 +18,7 @@ organized in a tree structure: ...@@ -18,7 +18,7 @@ organized in a tree structure:
+- ... +- ...
Every entry has its own dependencies. These dependencies are used Every entry has its own dependencies. These dependencies are used
to determine the visible of an entry. Any child entry is only to determine the visibility of an entry. Any child entry is only
visible if its parent entry is also visible. visible if its parent entry is also visible.
Menu entries Menu entries
...@@ -50,7 +50,7 @@ applicable everywhere (see syntax). ...@@ -50,7 +50,7 @@ applicable everywhere (see syntax).
- type definition: "bool"/"tristate"/"string"/"hex"/"integer" - type definition: "bool"/"tristate"/"string"/"hex"/"integer"
Every config option must have a type. There are only two basic types: Every config option must have a type. There are only two basic types:
tristate and string, the other types base on these two. The type tristate and string, the other types are based on these two. The type
definition optionally accepts an input prompt, so these two examples definition optionally accepts an input prompt, so these two examples
are equivalent: are equivalent:
...@@ -64,7 +64,7 @@ applicable everywhere (see syntax). ...@@ -64,7 +64,7 @@ applicable everywhere (see syntax).
to the user. Optionally dependencies only for this prompt can be added to the user. Optionally dependencies only for this prompt can be added
with "if". with "if".
- default value: "default" <symbol> ["if" <expr>] - default value: "default" <expr> ["if" <expr>]
A config option can have any number of default values. If multiple A config option can have any number of default values. If multiple
default values are visible, only the first defined one is active. default values are visible, only the first defined one is active.
Default values are not limited to the menu entry, where they are Default values are not limited to the menu entry, where they are
...@@ -81,7 +81,7 @@ applicable everywhere (see syntax). ...@@ -81,7 +81,7 @@ applicable everywhere (see syntax).
This defines a dependency for this menu entry. If multiple This defines a dependency for this menu entry. If multiple
dependencies are defined they are connected with '&&'. Dependencies dependencies are defined they are connected with '&&'. Dependencies
are applied to all other options within this menu entry (which also are applied to all other options within this menu entry (which also
accept "if" expression), so these two examples are equivalent: accept an "if" expression), so these two examples are equivalent:
bool "foo" if BAR bool "foo" if BAR
default y if BAR default y if BAR
...@@ -90,9 +90,24 @@ applicable everywhere (see syntax). ...@@ -90,9 +90,24 @@ applicable everywhere (see syntax).
bool "foo" bool "foo"
default y default y
- reverse dependencies: "select" <symbol> ["if" <expr>]
While normal dependencies reduce the upper limit of a symbol (see
below), reverse dependencies can be used to force a lower limit of
another symbol. The value of the current menu symbol is used as the
minimal value <symbol> can be set to. If <symbol> is selected multiple
times, the limit is set to the largest selection.
Reverse dependencies can only be used with boolean or tristate
symbols.
- numerical ranges: "range" <symbol> <symbol> ["if" <expr>]
This allows to limit the range of possible input values for integer
and hex symbols. The user can only input a value which is larger than
or equal to the first symbol and smaller than or equal to the second
symbol.
- help text: "help" - help text: "help"
This defines a help text. The end of the help text is determined by This defines a help text. The end of the help text is determined by
the level indentation, this means it ends at the first line which has the indentation level, this means it ends at the first line which has
a smaller indentation than the first line of the help text. a smaller indentation than the first line of the help text.
...@@ -123,14 +138,14 @@ Expressions are listed in decreasing order of precedence. ...@@ -123,14 +138,14 @@ Expressions are listed in decreasing order of precedence.
otherwise 'y'. otherwise 'y'.
(4) Returns the value of the expression. Used to override precedence. (4) Returns the value of the expression. Used to override precedence.
(5) Returns the result of (2-/expr/). (5) Returns the result of (2-/expr/).
(6) Returns the result of min(/expr/, /expr/). (6) Returns the result of max(/expr/, /expr/).
(7) Returns the result of max(/expr/, /expr/). (7) Returns the result of min(/expr/, /expr/).
An expression can have a value of 'n', 'm' or 'y' (or 0, 1, 2 An expression can have a value of 'n', 'm' or 'y' (or 0, 1, 2
respectively for calculations). A menu entry becomes visible when it's respectively for calculations). A menu entry becomes visible when it's
expression evaluates to 'm' or 'y'. expression evaluates to 'm' or 'y'.
There are two type of symbols: constant and nonconstant symbols. There are two types of symbols: constant and nonconstant symbols.
Nonconstant symbols are the most common ones and are defined with the Nonconstant symbols are the most common ones and are defined with the
'config' statement. Nonconstant symbols consist entirely of alphanumeric 'config' statement. Nonconstant symbols consist entirely of alphanumeric
characters or underscores. characters or underscores.
...@@ -159,8 +174,8 @@ dependency list of the config option NETDEVICES. ...@@ -159,8 +174,8 @@ dependency list of the config option NETDEVICES.
The other way to generate the menu structure is done by analyzing the The other way to generate the menu structure is done by analyzing the
dependencies. If a menu entry somehow depends on the previous entry, it dependencies. If a menu entry somehow depends on the previous entry, it
can be made a submenu of it. First the the previous (parent) symbol must can be made a submenu of it. First, the previous (parent) symbol must
be part of the dependency list and then one of these two condititions be part of the dependency list and then one of these two conditions
must be true: must be true:
- the child entry must become invisible, if the parent is set to 'n' - the child entry must become invisible, if the parent is set to 'n'
- the child entry must only be visible, if the parent is visible - the child entry must only be visible, if the parent is visible
...@@ -177,7 +192,7 @@ comment "module support disabled" ...@@ -177,7 +192,7 @@ comment "module support disabled"
MODVERSIONS directly depends on MODULES, this means it's only visible if MODVERSIONS directly depends on MODULES, this means it's only visible if
MODULES is different from 'n'. The comment on the other hand is always MODULES is different from 'n'. The comment on the other hand is always
visible when MODULES it's visible (the (empty) dependency of MODULES is visible when MODULES is visible (the (empty) dependency of MODULES is
also part of the comment dependencies). also part of the comment dependencies).
...@@ -188,12 +203,13 @@ The configuration file describes a series of menu entries, where every ...@@ -188,12 +203,13 @@ The configuration file describes a series of menu entries, where every
line starts with a keyword (except help texts). The following keywords line starts with a keyword (except help texts). The following keywords
end a menu entry: end a menu entry:
- config - config
- menuconfig
- choice/endchoice - choice/endchoice
- comment - comment
- menu/endmenu - menu/endmenu
- if/endif - if/endif
- source - source
The first four also start the definition of a menu entry. The first five also start the definition of a menu entry.
config: config:
...@@ -203,6 +219,14 @@ config: ...@@ -203,6 +219,14 @@ config:
This defines a config symbol <symbol> and accepts any of above This defines a config symbol <symbol> and accepts any of above
attributes as options. attributes as options.
menuconfig:
"menuconfig" <symbol>
<config options>
This is similiar to the simple config entry above, but it also gives a
hint to front ends, that all suboptions should be displayed as a
separate list of options.
choices: choices:
"choice" "choice"
......
...@@ -352,16 +352,8 @@ static inline void balance_irq(int cpu, int irq) ...@@ -352,16 +352,8 @@ static inline void balance_irq(int cpu, int irq)
unsigned long allowed_mask; unsigned long allowed_mask;
unsigned int new_cpu; unsigned int new_cpu;
if (irqbalance_disabled == IRQBALANCE_CHECK_ARCH) if (irqbalance_disabled)
irqbalance_disabled = NO_BALANCE_IRQ;
if (irqbalance_disabled) {
static int warned;
if (warned == 0) {
printk("irqbalance disabled\n");
warned = 1;
}
return; return;
}
allowed_mask = cpu_online_map & irq_affinity[irq]; allowed_mask = cpu_online_map & irq_affinity[irq];
new_cpu = move(cpu, allowed_mask, now, 1); new_cpu = move(cpu, allowed_mask, now, 1);
...@@ -620,6 +612,9 @@ static int __init balanced_irq_init(void) ...@@ -620,6 +612,9 @@ static int __init balanced_irq_init(void)
struct cpuinfo_x86 *c; struct cpuinfo_x86 *c;
c = &boot_cpu_data; c = &boot_cpu_data;
/* When not overwritten by the command line ask subarchitecture. */
if (irqbalance_disabled == IRQBALANCE_CHECK_ARCH)
irqbalance_disabled = NO_BALANCE_IRQ;
if (irqbalance_disabled) if (irqbalance_disabled)
return 0; return 0;
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
* Default generic APIC driver. This handles upto 8 CPUs. * Default generic APIC driver. This handles upto 8 CPUs.
*/ */
#define APIC_DEFINITION 1 #define APIC_DEFINITION 1
#include <asm/mach-default/mach_apicdef.h>
#include <asm/genapic.h> #include <asm/genapic.h>
#include <asm/fixmap.h> #include <asm/fixmap.h>
#include <asm/apicdef.h> #include <asm/apicdef.h>
...@@ -10,7 +11,6 @@ ...@@ -10,7 +11,6 @@
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/init.h> #include <linux/init.h>
#include <asm/mach-default/mach_apic.h> #include <asm/mach-default/mach_apic.h>
#include <asm/mach-default/mach_apicdef.h>
#include <asm/mach-default/mach_ipi.h> #include <asm/mach-default/mach_ipi.h>
#include <asm/mach-default/mach_mpparse.h> #include <asm/mach-default/mach_mpparse.h>
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
struct mmu_gather mmu_gathers[NR_CPUS]; struct mmu_gather mmu_gathers[NR_CPUS];
/* References to section boundaries: */ /* References to section boundaries: */
extern char _stext, _etext, _edata, __init_begin, __init_end; extern char _stext, _etext, _edata, __init_begin, __init_end, _end;
extern void ia64_tlb_init (void); extern void ia64_tlb_init (void);
...@@ -583,6 +583,7 @@ mem_init (void) ...@@ -583,6 +583,7 @@ mem_init (void)
long reserved_pages, codesize, datasize, initsize; long reserved_pages, codesize, datasize, initsize;
unsigned long num_pgt_pages; unsigned long num_pgt_pages;
pg_data_t *pgdat; pg_data_t *pgdat;
static struct kcore_list kcore_mem, kcore_vmem, kcore_kernel;
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
/* /*
...@@ -601,6 +602,10 @@ mem_init (void) ...@@ -601,6 +602,10 @@ mem_init (void)
high_memory = __va(max_low_pfn * PAGE_SIZE); high_memory = __va(max_low_pfn * PAGE_SIZE);
kclist_add(&kcore_mem, __va(0), max_low_pfn * PAGE_SIZE);
kclist_add(&kcore_vmem, (void *)VMALLOC_START, VMALLOC_END-VMALLOC_START);
kclist_add(&kcore_kernel, &_stext, &_end - &_stext);
for_each_pgdat(pgdat) for_each_pgdat(pgdat)
totalram_pages += free_all_bootmem_node(pgdat); totalram_pages += free_all_bootmem_node(pgdat);
......
...@@ -1728,10 +1728,8 @@ int acsi_init( void ) ...@@ -1728,10 +1728,8 @@ int acsi_init( void )
sprintf(disk->disk_name, "ad%c", 'a'+i); sprintf(disk->disk_name, "ad%c", 'a'+i);
disk->major = ACSI_MAJOR; disk->major = ACSI_MAJOR;
disk->first_minor = i << 4; disk->first_minor = i << 4;
if (acsi_info[i].type != HARDDISK) { if (acsi_info[i].type != HARDDISK)
disk->minor_shift = 0;
disk->minors = 1; disk->minors = 1;
}
disk->fops = &acsi_fops; disk->fops = &acsi_fops;
disk->private_data = &acsi_info[i]; disk->private_data = &acsi_info[i];
set_capacity(disk, acsi_info[i].size); set_capacity(disk, acsi_info[i].size);
......
...@@ -538,8 +538,6 @@ struct gendisk *alloc_disk(int minors) ...@@ -538,8 +538,6 @@ struct gendisk *alloc_disk(int minors)
memset(disk->part, 0, size); memset(disk->part, 0, size);
} }
disk->minors = minors; disk->minors = minors;
while (minors >>= 1)
disk->minor_shift++;
kobj_set_kset_s(disk,block_subsys); kobj_set_kset_s(disk,block_subsys);
kobject_init(&disk->kobj); kobject_init(&disk->kobj);
rand_initialize_disk(disk); rand_initialize_disk(disk);
......
...@@ -3376,7 +3376,6 @@ static int ide_cdrom_attach (ide_drive_t *drive) ...@@ -3376,7 +3376,6 @@ static int ide_cdrom_attach (ide_drive_t *drive)
drive->driver_data = info; drive->driver_data = info;
DRIVER(drive)->busy++; DRIVER(drive)->busy++;
g->minors = 1; g->minors = 1;
g->minor_shift = 0;
snprintf(g->devfs_name, sizeof(g->devfs_name), snprintf(g->devfs_name, sizeof(g->devfs_name),
"%s/cd", drive->devfs_name); "%s/cd", drive->devfs_name);
g->driverfs_dev = &drive->gendev; g->driverfs_dev = &drive->gendev;
......
...@@ -1814,7 +1814,6 @@ static int idedisk_attach(ide_drive_t *drive) ...@@ -1814,7 +1814,6 @@ static int idedisk_attach(ide_drive_t *drive)
} }
DRIVER(drive)->busy--; DRIVER(drive)->busy--;
g->minors = 1 << PARTN_BITS; g->minors = 1 << PARTN_BITS;
g->minor_shift = PARTN_BITS;
strcpy(g->devfs_name, drive->devfs_name); strcpy(g->devfs_name, drive->devfs_name);
g->driverfs_dev = &drive->gendev; g->driverfs_dev = &drive->gendev;
g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0; g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0;
......
...@@ -2057,7 +2057,6 @@ static int idefloppy_attach (ide_drive_t *drive) ...@@ -2057,7 +2057,6 @@ static int idefloppy_attach (ide_drive_t *drive)
idefloppy_setup (drive, floppy); idefloppy_setup (drive, floppy);
DRIVER(drive)->busy--; DRIVER(drive)->busy--;
g->minors = 1 << PARTN_BITS; g->minors = 1 << PARTN_BITS;
g->minor_shift = PARTN_BITS;
g->driverfs_dev = &drive->gendev; g->driverfs_dev = &drive->gendev;
strcpy(g->devfs_name, drive->devfs_name); strcpy(g->devfs_name, drive->devfs_name);
g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0; g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0;
......
This diff is collapsed.
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
#define ETHER1394_GASP_SPECIFIER_ID_LO (ETHER1394_GASP_SPECIFIER_ID & 0xff) #define ETHER1394_GASP_SPECIFIER_ID_LO (ETHER1394_GASP_SPECIFIER_ID & 0xff)
#define ETHER1394_GASP_VERSION 1 #define ETHER1394_GASP_VERSION 1
#define ETHER1394_OVERHEAD (2 * sizeof(quadlet_t)) /* GASP header overhead */ #define ETHER1394_GASP_OVERHEAD (2 * sizeof(quadlet_t)) /* GASP header overhead */
/* Node set == 64 */ /* Node set == 64 */
#define NODE_SET (ALL_NODES + 1) #define NODE_SET (ALL_NODES + 1)
...@@ -56,10 +56,9 @@ struct pdg_list { ...@@ -56,10 +56,9 @@ struct pdg_list {
struct eth1394_priv { struct eth1394_priv {
struct net_device_stats stats; /* Device stats */ struct net_device_stats stats; /* Device stats */
struct hpsb_host *host; /* The card for this dev */ struct hpsb_host *host; /* The card for this dev */
unsigned char max_rec[NODE_SET];/* Max payload per node */ u16 maxpayload[NODE_SET]; /* Max payload per node */
unsigned char sspd[NODE_SET]; /* Max speed per node */ unsigned char sspd[NODE_SET]; /* Max speed per node */
u16 fifo_hi[ALL_NODES]; /* 16bit hi fifo offset per node */ u64 fifo[ALL_NODES]; /* FIFO offset per node */
u32 fifo_lo[ALL_NODES]; /* 32bit lo fifo offset per node */
u64 eui[ALL_NODES]; /* EUI-64 per node */ u64 eui[ALL_NODES]; /* EUI-64 per node */
spinlock_t lock; /* Private lock */ spinlock_t lock; /* Private lock */
int broadcast_channel; /* Async stream Broadcast Channel */ int broadcast_channel; /* Async stream Broadcast Channel */
...@@ -74,6 +73,21 @@ struct host_info { ...@@ -74,6 +73,21 @@ struct host_info {
struct net_device *dev; struct net_device *dev;
}; };
/* Define a fake hardware header format for the networking core. Note that
* header size cannot exceed 16 bytes as that is the size of the header cache.
* Also, we do not need the source address in the header so we omit it and
* keep the header to under 16 bytes */
#define ETH1394_ALEN (8)
#define ETH1394_HLEN (10)
struct eth1394hdr {
unsigned char h_dest[ETH1394_ALEN]; /* destination eth1394 addr */
unsigned short h_proto; /* packet type ID field */
} __attribute__((packed));
typedef enum {ETH1394_GASP, ETH1394_WRREQ} eth1394_tx_type; typedef enum {ETH1394_GASP, ETH1394_WRREQ} eth1394_tx_type;
/* IP1394 headers */ /* IP1394 headers */
......
...@@ -57,7 +57,6 @@ ...@@ -57,7 +57,6 @@
/* Maps speed values above to a string representation */ /* Maps speed values above to a string representation */
extern const char *hpsb_speedto_str[]; extern const char *hpsb_speedto_str[];
extern const u8 hpsb_speedto_maxrec[];
#define SELFID_PWRCL_NO_POWER 0x0 #define SELFID_PWRCL_NO_POWER 0x0
......
...@@ -61,7 +61,6 @@ static kmem_cache_t *hpsb_packet_cache; ...@@ -61,7 +61,6 @@ static kmem_cache_t *hpsb_packet_cache;
/* Some globals used */ /* Some globals used */
const char *hpsb_speedto_str[] = { "S100", "S200", "S400", "S800", "S1600", "S3200" }; const char *hpsb_speedto_str[] = { "S100", "S200", "S400", "S800", "S1600", "S3200" };
const u8 hpsb_speedto_maxrec[] = { 0x7, 0x8, 0x9, 0x10, 0x11, 0x12 };
static void dump_packet(const char *text, quadlet_t *data, int size) static void dump_packet(const char *text, quadlet_t *data, int size)
{ {
...@@ -1246,7 +1245,6 @@ EXPORT_SYMBOL(hpsb_unref_host); ...@@ -1246,7 +1245,6 @@ EXPORT_SYMBOL(hpsb_unref_host);
/** ieee1394_core.c **/ /** ieee1394_core.c **/
EXPORT_SYMBOL(hpsb_speedto_str); EXPORT_SYMBOL(hpsb_speedto_str);
EXPORT_SYMBOL(hpsb_speedto_maxrec);
EXPORT_SYMBOL(hpsb_set_packet_complete_task); EXPORT_SYMBOL(hpsb_set_packet_complete_task);
EXPORT_SYMBOL(alloc_hpsb_packet); EXPORT_SYMBOL(alloc_hpsb_packet);
EXPORT_SYMBOL(free_hpsb_packet); EXPORT_SYMBOL(free_hpsb_packet);
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
*/ */
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/sched.h>
#include "iso.h" #include "iso.h"
void hpsb_iso_stop(struct hpsb_iso *iso) void hpsb_iso_stop(struct hpsb_iso *iso)
......
...@@ -79,7 +79,7 @@ ...@@ -79,7 +79,7 @@
#include "sbp2.h" #include "sbp2.h"
static char version[] __devinitdata = static char version[] __devinitdata =
"$Rev: 938 $ Ben Collins <bcollins@debian.org>"; "$Rev: 942 $ Ben Collins <bcollins@debian.org>";
/* /*
* Module load parameter definitions * Module load parameter definitions
...@@ -230,6 +230,8 @@ static void sbp2scsi_complete_command(struct scsi_id_instance_data *scsi_id, ...@@ -230,6 +230,8 @@ static void sbp2scsi_complete_command(struct scsi_id_instance_data *scsi_id,
static Scsi_Host_Template scsi_driver_template; static Scsi_Host_Template scsi_driver_template;
const u8 sbp2_speedto_max_payload[] = { 0x7, 0x8, 0x9, 0xA, 0xB, 0xC };
static struct hpsb_highlevel sbp2_highlevel = { static struct hpsb_highlevel sbp2_highlevel = {
.name = SBP2_DEVICE_NAME, .name = SBP2_DEVICE_NAME,
.remove_host = sbp2_remove_host, .remove_host = sbp2_remove_host,
...@@ -779,7 +781,7 @@ static int sbp2_start_ud(struct sbp2scsi_host_info *hi, struct unit_directory *u ...@@ -779,7 +781,7 @@ static int sbp2_start_ud(struct sbp2scsi_host_info *hi, struct unit_directory *u
scsi_id->ne = ud->ne; scsi_id->ne = ud->ne;
scsi_id->hi = hi; scsi_id->hi = hi;
scsi_id->speed_code = SPEED_100; scsi_id->speed_code = SPEED_100;
scsi_id->max_payload_size = hpsb_speedto_maxrec[SPEED_100]; scsi_id->max_payload_size = sbp2_speedto_max_payload[SPEED_100];
atomic_set(&scsi_id->sbp2_login_complete, 0); atomic_set(&scsi_id->sbp2_login_complete, 0);
INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_inuse); INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_inuse);
INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_completed); INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_completed);
...@@ -1690,7 +1692,7 @@ static int sbp2_max_speed_and_size(struct scsi_id_instance_data *scsi_id) ...@@ -1690,7 +1692,7 @@ static int sbp2_max_speed_and_size(struct scsi_id_instance_data *scsi_id)
/* Payload size is the lesser of what our speed supports and what /* Payload size is the lesser of what our speed supports and what
* our host supports. */ * our host supports. */
scsi_id->max_payload_size = min(hpsb_speedto_maxrec[scsi_id->speed_code], scsi_id->max_payload_size = min(sbp2_speedto_max_payload[scsi_id->speed_code],
(u8)(((be32_to_cpu(hi->host->csr.rom[2]) >> 12) & 0xf) - 1)); (u8)(((be32_to_cpu(hi->host->csr.rom[2]) >> 12) & 0xf) - 1));
SBP2_ERR("Node[" NODE_BUS_FMT "]: Max speed [%s] - Max payload [%u]", SBP2_ERR("Node[" NODE_BUS_FMT "]: Max speed [%s] - Max payload [%u]",
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <asm/io.h> #include <asm/io.h>
#include <linux/mtd/map.h> #include <linux/mtd/map.h>
#include <linux/mtd/cfi.h>
static u8 simple_map_read8(struct map_info *map, unsigned long ofs) static u8 simple_map_read8(struct map_info *map, unsigned long ofs)
{ {
......
...@@ -150,6 +150,14 @@ struct eventpoll { ...@@ -150,6 +150,14 @@ struct eventpoll {
/* Protect the this structure access */ /* Protect the this structure access */
rwlock_t lock; rwlock_t lock;
/*
* This semaphore is used to ensure that files are not removed
* while epoll is using them. This is read-held during the event
* collection loop and it is write-held during the file cleanup
* path, the epoll file exit code and the ctl operations.
*/
struct rw_semaphore sem;
/* Wait queue used by sys_epoll_wait() */ /* Wait queue used by sys_epoll_wait() */
wait_queue_head_t wq; wait_queue_head_t wq;
...@@ -279,16 +287,6 @@ static struct super_block *eventpollfs_get_sb(struct file_system_type *fs_type, ...@@ -279,16 +287,6 @@ static struct super_block *eventpollfs_get_sb(struct file_system_type *fs_type,
/* Safe wake up implementation */ /* Safe wake up implementation */
static struct poll_safewake psw; static struct poll_safewake psw;
/*
* This semaphore is used to ensure that files are not removed
* while epoll is using them. Namely the f_op->poll(), since
* it has to be called from outside the lock, must be protected.
* This is read-held during the event transfer loop to userspace
* and it is write-held during the file cleanup path and the epoll
* file exit code.
*/
static struct rw_semaphore epsem;
/* Slab cache used to allocate "struct epitem" */ /* Slab cache used to allocate "struct epitem" */
static kmem_cache_t *epi_cache; static kmem_cache_t *epi_cache;
...@@ -357,15 +355,14 @@ static void ep_poll_safewake(struct poll_safewake *psw, wait_queue_head_t *wq) ...@@ -357,15 +355,14 @@ static void ep_poll_safewake(struct poll_safewake *psw, wait_queue_head_t *wq)
list_for_each(lnk, lsthead) { list_for_each(lnk, lsthead) {
tncur = list_entry(lnk, struct wake_task_node, llink); tncur = list_entry(lnk, struct wake_task_node, llink);
if (tncur->task == this_task) { if (tncur->wq == wq ||
if (tncur->wq == wq || ++wake_nests > EP_MAX_POLLWAKE_NESTS) { (tncur->task == this_task && ++wake_nests > EP_MAX_POLLWAKE_NESTS)) {
/* /*
* Ops ... loop detected or maximum nest level reached. * Ops ... loop detected or maximum nest level reached.
* We abort this wake by breaking the cycle itself. * We abort this wake by breaking the cycle itself.
*/ */
spin_unlock_irqrestore(&psw->lock, flags); spin_unlock_irqrestore(&psw->lock, flags);
return; return;
}
} }
} }
...@@ -437,14 +434,15 @@ void eventpoll_release(struct file *file) ...@@ -437,14 +434,15 @@ void eventpoll_release(struct file *file)
* The only hit might come from ep_free() but by holding the semaphore * The only hit might come from ep_free() but by holding the semaphore
* will correctly serialize the operation. * will correctly serialize the operation.
*/ */
down_write(&epsem);
while (!list_empty(lsthead)) { while (!list_empty(lsthead)) {
epi = list_entry(lsthead->next, struct epitem, fllink); epi = list_entry(lsthead->next, struct epitem, fllink);
EP_LIST_DEL(&epi->fllink); EP_LIST_DEL(&epi->fllink);
down_write(&epi->ep->sem);
ep_remove(epi->ep, epi); ep_remove(epi->ep, epi);
up_write(&epi->ep->sem);
} }
up_write(&epsem);
} }
...@@ -568,9 +566,18 @@ asmlinkage long sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event *even ...@@ -568,9 +566,18 @@ asmlinkage long sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event *even
error = -EEXIST; error = -EEXIST;
break; break;
case EPOLL_CTL_DEL: case EPOLL_CTL_DEL:
if (epi) if (epi) {
/*
* We need to protect the remove operation because another
* thread might be doing an epoll_wait() and using the
* target file.
*/
down_write(&ep->sem);
error = ep_remove(ep, epi); error = ep_remove(ep, epi);
else
up_write(&ep->sem);
} else
error = -ENOENT; error = -ENOENT;
break; break;
case EPOLL_CTL_MOD: case EPOLL_CTL_MOD:
...@@ -703,10 +710,6 @@ static int ep_getfd(int *efd, struct inode **einode, struct file **efile) ...@@ -703,10 +710,6 @@ static int ep_getfd(int *efd, struct inode **einode, struct file **efile)
file->f_vfsmnt = mntget(eventpoll_mnt); file->f_vfsmnt = mntget(eventpoll_mnt);
file->f_dentry = dget(dentry); file->f_dentry = dget(dentry);
/*
* Initialize the file as read/write because it could be used
* with write() to add/remove/change interest sets.
*/
file->f_pos = 0; file->f_pos = 0;
file->f_flags = O_RDONLY; file->f_flags = O_RDONLY;
file->f_op = &eventpoll_fops; file->f_op = &eventpoll_fops;
...@@ -815,6 +818,7 @@ static int ep_init(struct eventpoll *ep, unsigned int hashbits) ...@@ -815,6 +818,7 @@ static int ep_init(struct eventpoll *ep, unsigned int hashbits)
unsigned int i, hsize; unsigned int i, hsize;
rwlock_init(&ep->lock); rwlock_init(&ep->lock);
init_rwsem(&ep->sem);
init_waitqueue_head(&ep->wq); init_waitqueue_head(&ep->wq);
init_waitqueue_head(&ep->poll_wait); init_waitqueue_head(&ep->poll_wait);
INIT_LIST_HEAD(&ep->rdllist); INIT_LIST_HEAD(&ep->rdllist);
...@@ -841,11 +845,15 @@ static void ep_free(struct eventpoll *ep) ...@@ -841,11 +845,15 @@ static void ep_free(struct eventpoll *ep)
struct list_head *lsthead, *lnk; struct list_head *lsthead, *lnk;
struct epitem *epi; struct epitem *epi;
/* We need to release all tasks waiting for these file */
if (waitqueue_active(&ep->poll_wait))
ep_poll_safewake(&psw, &ep->poll_wait);
/* /*
* We need to lock this because we could be hit by * We need to lock this because we could be hit by
* eventpoll_release() while we're freeing the "struct eventpoll". * eventpoll_release() while we're freeing the "struct eventpoll".
*/ */
down_write(&epsem); down_write(&ep->sem);
/* /*
* Walks through the whole hash by unregistering poll callbacks. * Walks through the whole hash by unregistering poll callbacks.
...@@ -863,7 +871,7 @@ static void ep_free(struct eventpoll *ep) ...@@ -863,7 +871,7 @@ static void ep_free(struct eventpoll *ep)
/* /*
* Walks through the whole hash by freeing each "struct epitem". At this * Walks through the whole hash by freeing each "struct epitem". At this
* point we are sure no poll callbacks will be lingering around, and also by * point we are sure no poll callbacks will be lingering around, and also by
* write-holding "epsem" we can be sure that no file cleanup code will hit * write-holding "sem" we can be sure that no file cleanup code will hit
* us during this operation. So we can avoid the lock on "ep->lock". * us during this operation. So we can avoid the lock on "ep->lock".
*/ */
for (i = 0, hsize = 1 << ep->hashbits; i < hsize; i++) { for (i = 0, hsize = 1 << ep->hashbits; i < hsize; i++) {
...@@ -876,7 +884,7 @@ static void ep_free(struct eventpoll *ep) ...@@ -876,7 +884,7 @@ static void ep_free(struct eventpoll *ep)
} }
} }
up_write(&epsem); up_write(&ep->sem);
/* Free hash pages */ /* Free hash pages */
ep_free_pages(ep->hpages, EP_HASH_PAGES(ep->hashbits)); ep_free_pages(ep->hpages, EP_HASH_PAGES(ep->hashbits));
...@@ -1337,20 +1345,6 @@ static int ep_collect_ready_items(struct eventpoll *ep, struct list_head *txlist ...@@ -1337,20 +1345,6 @@ static int ep_collect_ready_items(struct eventpoll *ep, struct list_head *txlist
/* If this file is already in the ready list we exit soon */ /* If this file is already in the ready list we exit soon */
if (!EP_IS_LINKED(&epi->txlink)) { if (!EP_IS_LINKED(&epi->txlink)) {
/*
* We need to increase the usage count of the "struct epitem" because
* another thread might call EPOLL_CTL_DEL on this target and make the
* object to vanish underneath our nose.
*/
ep_use_epitem(epi);
/*
* We need to increase the usage count of the "struct file" because
* another thread might call close() on this target and make the file
* to vanish before we will be able to call f_op->poll().
*/
get_file(epi->file);
/* /*
* This is initialized in this way so that the default * This is initialized in this way so that the default
* behaviour of the reinjecting code will be to push back * behaviour of the reinjecting code will be to push back
...@@ -1389,19 +1383,21 @@ static int ep_send_events(struct eventpoll *ep, struct list_head *txlist, ...@@ -1389,19 +1383,21 @@ static int ep_send_events(struct eventpoll *ep, struct list_head *txlist,
struct epitem *epi; struct epitem *epi;
struct epoll_event event[EP_MAX_BUF_EVENTS]; struct epoll_event event[EP_MAX_BUF_EVENTS];
/*
* We can loop without lock because this is a task private list.
* The test done during the collection loop will guarantee us that
* another task will not try to collect this file. Also, items
* cannot vanish during the loop because we are holding "sem".
*/
list_for_each(lnk, txlist) { list_for_each(lnk, txlist) {
epi = list_entry(lnk, struct epitem, txlink); epi = list_entry(lnk, struct epitem, txlink);
/* Get the ready file event set */
revents = epi->file->f_op->poll(epi->file, NULL);
/* /*
* Release the file usage before checking the event mask. * Get the ready file event set. We can safely use the file
* In case this call will lead to the file removal, its * because we are holding the "sem" in read and this will
* ->event.events member has been already set to zero and * guarantee that both the file and the item will not vanish.
* this will make the event to be dropped.
*/ */
fput(epi->file); revents = epi->file->f_op->poll(epi->file, NULL);
/* /*
* Set the return event set for the current file descriptor. * Set the return event set for the current file descriptor.
...@@ -1416,17 +1412,8 @@ static int ep_send_events(struct eventpoll *ep, struct list_head *txlist, ...@@ -1416,17 +1412,8 @@ static int ep_send_events(struct eventpoll *ep, struct list_head *txlist,
eventbuf++; eventbuf++;
if (eventbuf == EP_MAX_BUF_EVENTS) { if (eventbuf == EP_MAX_BUF_EVENTS) {
if (__copy_to_user(&events[eventcnt], event, if (__copy_to_user(&events[eventcnt], event,
eventbuf * sizeof(struct epoll_event))) { eventbuf * sizeof(struct epoll_event)))
/*
* We need to complete the loop to decrement the file
* usage before returning from this function.
*/
for (lnk = lnk->next; lnk != txlist; lnk = lnk->next) {
epi = list_entry(lnk, struct epitem, txlink);
fput(epi->file);
}
return -EFAULT; return -EFAULT;
}
eventcnt += eventbuf; eventcnt += eventbuf;
eventbuf = 0; eventbuf = 0;
} }
...@@ -1447,7 +1434,8 @@ static int ep_send_events(struct eventpoll *ep, struct list_head *txlist, ...@@ -1447,7 +1434,8 @@ static int ep_send_events(struct eventpoll *ep, struct list_head *txlist,
/* /*
* Walk through the transfer list we collected with ep_collect_ready_items() * Walk through the transfer list we collected with ep_collect_ready_items()
* and, if 1) the item is still "alive" 2) its event set is not empty 3) it's * and, if 1) the item is still "alive" 2) its event set is not empty 3) it's
* not already linked, links it to the ready list. * not already linked, links it to the ready list. Same as above, we are holding
* "sem" so items cannot vanish underneath our nose.
*/ */
static void ep_reinject_items(struct eventpoll *ep, struct list_head *txlist) static void ep_reinject_items(struct eventpoll *ep, struct list_head *txlist)
{ {
...@@ -1475,8 +1463,6 @@ static void ep_reinject_items(struct eventpoll *ep, struct list_head *txlist) ...@@ -1475,8 +1463,6 @@ static void ep_reinject_items(struct eventpoll *ep, struct list_head *txlist)
list_add_tail(&epi->rdllink, &ep->rdllist); list_add_tail(&epi->rdllink, &ep->rdllist);
ricnt++; ricnt++;
} }
ep_release_epitem(epi);
} }
if (ricnt) { if (ricnt) {
...@@ -1510,17 +1496,12 @@ static int ep_events_transfer(struct eventpoll *ep, struct epoll_event *events, ...@@ -1510,17 +1496,12 @@ static int ep_events_transfer(struct eventpoll *ep, struct epoll_event *events,
/* /*
* We need to lock this because we could be hit by * We need to lock this because we could be hit by
* eventpoll_release() while we're transfering * eventpoll_release() and epoll_ctl(EPOLL_CTL_DEL).
* events to userspace. Read-holding "epsem" will lock
* out eventpoll_release() during the whole
* transfer loop and this will garantie us that the
* file will not vanish underneath our nose when
* we will call f_op->poll() from ep_send_events().
*/ */
down_read(&epsem); down_read(&ep->sem);
/* Collect/extract ready items */ /* Collect/extract ready items */
if (ep_collect_ready_items(ep, &txlist, maxevents)) { if (ep_collect_ready_items(ep, &txlist, maxevents) > 0) {
/* Build result set in userspace */ /* Build result set in userspace */
eventcnt = ep_send_events(ep, &txlist, events); eventcnt = ep_send_events(ep, &txlist, events);
...@@ -1528,7 +1509,7 @@ static int ep_events_transfer(struct eventpoll *ep, struct epoll_event *events, ...@@ -1528,7 +1509,7 @@ static int ep_events_transfer(struct eventpoll *ep, struct epoll_event *events,
ep_reinject_items(ep, &txlist); ep_reinject_items(ep, &txlist);
} }
up_read(&epsem); up_read(&ep->sem);
return eventcnt; return eventcnt;
} }
...@@ -1652,9 +1633,6 @@ static int __init eventpoll_init(void) ...@@ -1652,9 +1633,6 @@ static int __init eventpoll_init(void)
{ {
int error; int error;
/* Initialize the semaphore used to syncronize the file cleanup code */
init_rwsem(&epsem);
/* Initialize the structure used to perform safe poll wait head wake ups */ /* Initialize the structure used to perform safe poll wait head wake ups */
ep_poll_safewake_init(&psw); ep_poll_safewake_init(&psw);
......
...@@ -1262,6 +1262,13 @@ static int bput_one(handle_t *handle, struct buffer_head *bh) ...@@ -1262,6 +1262,13 @@ static int bput_one(handle_t *handle, struct buffer_head *bh)
return 0; return 0;
} }
static int journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh)
{
if (buffer_mapped(bh))
return ext3_journal_dirty_data(handle, bh);
return 0;
}
/* /*
* Note that we always start a transaction even if we're not journalling * Note that we always start a transaction even if we're not journalling
* data. This is to preserve ordering: any hole instantiation within * data. This is to preserve ordering: any hole instantiation within
...@@ -1381,7 +1388,7 @@ static int ext3_writepage(struct page *page, struct writeback_control *wbc) ...@@ -1381,7 +1388,7 @@ static int ext3_writepage(struct page *page, struct writeback_control *wbc)
if (ret == 0) { if (ret == 0) {
err = walk_page_buffers(handle, page_bufs, err = walk_page_buffers(handle, page_bufs,
0, PAGE_CACHE_SIZE, NULL, 0, PAGE_CACHE_SIZE, NULL,
ext3_journal_dirty_data); journal_dirty_data_fn);
if (!ret) if (!ret)
ret = err; ret = err;
} }
......
...@@ -99,7 +99,12 @@ static ssize_t read_kcore(struct file *file, char *buf, size_t count, loff_t *pp ...@@ -99,7 +99,12 @@ static ssize_t read_kcore(struct file *file, char *buf, size_t count, loff_t *pp
} }
#else /* CONFIG_KCORE_AOUT */ #else /* CONFIG_KCORE_AOUT */
#define KCORE_BASE PAGE_OFFSET #ifndef kc_vaddr_to_offset
#define kc_vaddr_to_offset(v) ((v) - PAGE_OFFSET)
#endif
#ifndef kc_offset_to_vaddr
#define kc_offset_to_vaddr(o) ((o) + PAGE_OFFSET)
#endif
#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) #define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
...@@ -112,29 +117,60 @@ struct memelfnote ...@@ -112,29 +117,60 @@ struct memelfnote
void *data; void *data;
}; };
static struct kcore_list *kclist;
static rwlock_t kclist_lock = RW_LOCK_UNLOCKED;
void
kclist_add(struct kcore_list *new, void *addr, size_t size)
{
new->addr = (unsigned long)addr;
new->size = size;
write_lock(&kclist_lock);
new->next = kclist;
kclist = new;
write_unlock(&kclist_lock);
}
struct kcore_list *
kclist_del(void *addr)
{
struct kcore_list *m, **p = &kclist;
write_lock(&kclist_lock);
for (m = *p; m; p = &m->next) {
if (m->addr == (unsigned long)addr) {
*p = m->next;
write_unlock(&kclist_lock);
return m;
}
}
write_unlock(&kclist_lock);
return 0;
}
extern char saved_command_line[]; extern char saved_command_line[];
static size_t get_kcore_size(int *num_vma, size_t *elf_buflen) static size_t get_kcore_size(int *nphdr, size_t *elf_buflen)
{ {
size_t try, size; size_t try, size;
struct vm_struct *m; struct kcore_list *m;
*num_vma = 0; *nphdr = 1; /* PT_NOTE */
size = ((size_t)high_memory - KCORE_BASE + PAGE_SIZE); size = 0;
if (!vmlist) {
*elf_buflen = PAGE_SIZE;
return (size);
}
for (m=vmlist; m; m=m->next) { for (m=kclist; m; m=m->next) {
try = (size_t)m->addr + m->size; try = kc_vaddr_to_offset((size_t)m->addr + m->size);
if (try > KCORE_BASE + size) if (try > size)
size = try - KCORE_BASE; size = try;
*num_vma = *num_vma + 1; *nphdr = *nphdr + 1;
} }
*elf_buflen = sizeof(struct elfhdr) + *elf_buflen = sizeof(struct elfhdr) +
(*num_vma + 2)*sizeof(struct elf_phdr) + (*nphdr + 2)*sizeof(struct elf_phdr) +
3 * sizeof(struct memelfnote); 3 * sizeof(struct memelfnote) +
sizeof(struct elf_prstatus) +
sizeof(struct elf_prpsinfo) +
sizeof(struct task_struct);
*elf_buflen = PAGE_ALIGN(*elf_buflen); *elf_buflen = PAGE_ALIGN(*elf_buflen);
return size + *elf_buflen; return size + *elf_buflen;
} }
...@@ -184,9 +220,9 @@ static char *storenote(struct memelfnote *men, char *bufp) ...@@ -184,9 +220,9 @@ static char *storenote(struct memelfnote *men, char *bufp)
/* /*
* store an ELF coredump header in the supplied buffer * store an ELF coredump header in the supplied buffer
* num_vma is the number of elements in vmlist * nphdr is the number of elf_phdr to insert
*/ */
static void elf_kcore_store_hdr(char *bufp, int num_vma, int dataoff) static void elf_kcore_store_hdr(char *bufp, int nphdr, int dataoff)
{ {
struct elf_prstatus prstatus; /* NT_PRSTATUS */ struct elf_prstatus prstatus; /* NT_PRSTATUS */
struct elf_prpsinfo prpsinfo; /* NT_PRPSINFO */ struct elf_prpsinfo prpsinfo; /* NT_PRPSINFO */
...@@ -194,7 +230,7 @@ static void elf_kcore_store_hdr(char *bufp, int num_vma, int dataoff) ...@@ -194,7 +230,7 @@ static void elf_kcore_store_hdr(char *bufp, int num_vma, int dataoff)
struct elfhdr *elf; struct elfhdr *elf;
struct memelfnote notes[3]; struct memelfnote notes[3];
off_t offset = 0; off_t offset = 0;
struct vm_struct *m; struct kcore_list *m;
/* setup ELF header */ /* setup ELF header */
elf = (struct elfhdr *) bufp; elf = (struct elfhdr *) bufp;
...@@ -214,7 +250,7 @@ static void elf_kcore_store_hdr(char *bufp, int num_vma, int dataoff) ...@@ -214,7 +250,7 @@ static void elf_kcore_store_hdr(char *bufp, int num_vma, int dataoff)
elf->e_flags = 0; elf->e_flags = 0;
elf->e_ehsize = sizeof(struct elfhdr); elf->e_ehsize = sizeof(struct elfhdr);
elf->e_phentsize= sizeof(struct elf_phdr); elf->e_phentsize= sizeof(struct elf_phdr);
elf->e_phnum = 2 + num_vma; elf->e_phnum = nphdr;
elf->e_shentsize= 0; elf->e_shentsize= 0;
elf->e_shnum = 0; elf->e_shnum = 0;
elf->e_shstrndx = 0; elf->e_shstrndx = 0;
...@@ -232,33 +268,17 @@ static void elf_kcore_store_hdr(char *bufp, int num_vma, int dataoff) ...@@ -232,33 +268,17 @@ static void elf_kcore_store_hdr(char *bufp, int num_vma, int dataoff)
nhdr->p_flags = 0; nhdr->p_flags = 0;
nhdr->p_align = 0; nhdr->p_align = 0;
/* setup ELF PT_LOAD program header for the /* setup ELF PT_LOAD program header for every area */
* virtual range 0xc0000000 -> high_memory */ for (m=kclist; m; m=m->next) {
phdr = (struct elf_phdr *) bufp;
bufp += sizeof(struct elf_phdr);
offset += sizeof(struct elf_phdr);
phdr->p_type = PT_LOAD;
phdr->p_flags = PF_R|PF_W|PF_X;
phdr->p_offset = PAGE_OFFSET - KCORE_BASE + dataoff;
phdr->p_vaddr = PAGE_OFFSET;
phdr->p_paddr = __pa(PAGE_OFFSET);
phdr->p_filesz = phdr->p_memsz = ((unsigned long)high_memory - PAGE_OFFSET);
phdr->p_align = PAGE_SIZE;
/* setup ELF PT_LOAD program header for every vmalloc'd area */
for (m=vmlist; m; m=m->next) {
if (m->flags & VM_IOREMAP) /* don't dump ioremap'd stuff! (TA) */
continue;
phdr = (struct elf_phdr *) bufp; phdr = (struct elf_phdr *) bufp;
bufp += sizeof(struct elf_phdr); bufp += sizeof(struct elf_phdr);
offset += sizeof(struct elf_phdr); offset += sizeof(struct elf_phdr);
phdr->p_type = PT_LOAD; phdr->p_type = PT_LOAD;
phdr->p_flags = PF_R|PF_W|PF_X; phdr->p_flags = PF_R|PF_W|PF_X;
phdr->p_offset = (size_t)m->addr - KCORE_BASE + dataoff; phdr->p_offset = kc_vaddr_to_offset(m->addr) + dataoff;
phdr->p_vaddr = (size_t)m->addr; phdr->p_vaddr = (size_t)m->addr;
phdr->p_paddr = __pa(m->addr); phdr->p_paddr = 0;
phdr->p_filesz = phdr->p_memsz = m->size; phdr->p_filesz = phdr->p_memsz = m->size;
phdr->p_align = PAGE_SIZE; phdr->p_align = PAGE_SIZE;
} }
...@@ -294,7 +314,7 @@ static void elf_kcore_store_hdr(char *bufp, int num_vma, int dataoff) ...@@ -294,7 +314,7 @@ static void elf_kcore_store_hdr(char *bufp, int num_vma, int dataoff)
strcpy(prpsinfo.pr_fname, "vmlinux"); strcpy(prpsinfo.pr_fname, "vmlinux");
strncpy(prpsinfo.pr_psargs, saved_command_line, ELF_PRARGSZ); strncpy(prpsinfo.pr_psargs, saved_command_line, ELF_PRARGSZ);
nhdr->p_filesz = notesize(&notes[1]); nhdr->p_filesz += notesize(&notes[1]);
bufp = storenote(&notes[1], bufp); bufp = storenote(&notes[1], bufp);
/* set up the task structure */ /* set up the task structure */
...@@ -303,7 +323,7 @@ static void elf_kcore_store_hdr(char *bufp, int num_vma, int dataoff) ...@@ -303,7 +323,7 @@ static void elf_kcore_store_hdr(char *bufp, int num_vma, int dataoff)
notes[2].datasz = sizeof(struct task_struct); notes[2].datasz = sizeof(struct task_struct);
notes[2].data = current; notes[2].data = current;
nhdr->p_filesz = notesize(&notes[2]); nhdr->p_filesz += notesize(&notes[2]);
bufp = storenote(&notes[2], bufp); bufp = storenote(&notes[2], bufp);
} /* end elf_kcore_store_hdr() */ } /* end elf_kcore_store_hdr() */
...@@ -317,13 +337,14 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t ...@@ -317,13 +337,14 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t
ssize_t acc = 0; ssize_t acc = 0;
size_t size, tsz; size_t size, tsz;
size_t elf_buflen; size_t elf_buflen;
int num_vma; int nphdr;
unsigned long start; unsigned long start;
read_lock(&vmlist_lock); read_lock(&kclist_lock);
proc_root_kcore->size = size = get_kcore_size(&num_vma, &elf_buflen); tsz = get_kcore_size(&nphdr, &elf_buflen);
proc_root_kcore->size = size = tsz + elf_buflen;
if (buflen == 0 || *fpos >= size) { if (buflen == 0 || *fpos >= size) {
read_unlock(&vmlist_lock); read_unlock(&kclist_lock);
return 0; return 0;
} }
...@@ -340,12 +361,12 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t ...@@ -340,12 +361,12 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t
tsz = buflen; tsz = buflen;
elf_buf = kmalloc(elf_buflen, GFP_ATOMIC); elf_buf = kmalloc(elf_buflen, GFP_ATOMIC);
if (!elf_buf) { if (!elf_buf) {
read_unlock(&vmlist_lock); read_unlock(&kclist_lock);
return -ENOMEM; return -ENOMEM;
} }
memset(elf_buf, 0, elf_buflen); memset(elf_buf, 0, elf_buflen);
elf_kcore_store_hdr(elf_buf, num_vma, elf_buflen); elf_kcore_store_hdr(elf_buf, nphdr, elf_buflen);
read_unlock(&vmlist_lock); read_unlock(&kclist_lock);
if (copy_to_user(buffer, elf_buf + *fpos, tsz)) { if (copy_to_user(buffer, elf_buf + *fpos, tsz)) {
kfree(elf_buf); kfree(elf_buf);
return -EFAULT; return -EFAULT;
...@@ -360,41 +381,30 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t ...@@ -360,41 +381,30 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t
if (buflen == 0) if (buflen == 0)
return acc; return acc;
} else } else
read_unlock(&vmlist_lock); read_unlock(&kclist_lock);
/* where page 0 not mapped, write zeros into buffer */
#if defined (__i386__) || defined (__mc68000__) || defined(__x86_64__)
if (*fpos < PAGE_SIZE + elf_buflen) {
/* work out how much to clear */
tsz = PAGE_SIZE + elf_buflen - *fpos;
if (buflen < tsz)
tsz = buflen;
/* write zeros to buffer */
if (clear_user(buffer, tsz))
return -EFAULT;
buflen -= tsz;
*fpos += tsz;
buffer += tsz;
acc += tsz;
/* leave now if filled buffer already */
if (buflen == 0)
return tsz;
}
#endif
/* /*
* Fill the remainder of the buffer from kernel VM space. * Check to see if our file offset matches with any of
* We said in the ELF header that the data which starts * the addresses in the elf_phdr on our list.
* at 'elf_buflen' is virtual address KCORE_BASE. --rmk
*/ */
start = KCORE_BASE + (*fpos - elf_buflen); start = kc_offset_to_vaddr(*fpos - elf_buflen);
if ((tsz = (PAGE_SIZE - (start & ~PAGE_MASK))) > buflen) if ((tsz = (PAGE_SIZE - (start & ~PAGE_MASK))) > buflen)
tsz = buflen; tsz = buflen;
while (buflen) { while (buflen) {
if ((start >= VMALLOC_START) && (start < VMALLOC_END)) { struct kcore_list *m;
read_lock(&kclist_lock);
for (m=kclist; m; m=m->next) {
if (start >= m->addr && start < (m->addr+m->size))
break;
}
read_unlock(&kclist_lock);
if (m == NULL) {
if (clear_user(buffer, tsz))
return -EFAULT;
} else if ((start >= VMALLOC_START) && (start < VMALLOC_END)) {
char * elf_buf; char * elf_buf;
struct vm_struct *m; struct vm_struct *m;
unsigned long curstart = start; unsigned long curstart = start;
...@@ -439,8 +449,7 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t ...@@ -439,8 +449,7 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t
return -EFAULT; return -EFAULT;
} }
kfree(elf_buf); kfree(elf_buf);
} else if ((start > PAGE_OFFSET) && (start < } else {
(unsigned long)high_memory)) {
if (kern_addr_valid(start)) { if (kern_addr_valid(start)) {
if (copy_to_user(buffer, (char *)start, tsz)) if (copy_to_user(buffer, (char *)start, tsz))
return -EFAULT; return -EFAULT;
...@@ -448,9 +457,6 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t ...@@ -448,9 +457,6 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t
if (clear_user(buffer, tsz)) if (clear_user(buffer, tsz))
return -EFAULT; return -EFAULT;
} }
} else {
if (clear_user(buffer, tsz))
return -EFAULT;
} }
buflen -= tsz; buflen -= tsz;
*fpos += tsz; *fpos += tsz;
......
...@@ -24,8 +24,6 @@ ...@@ -24,8 +24,6 @@
#define check_apicid_present (genapic->check_apicid_present) #define check_apicid_present (genapic->check_apicid_present)
#define check_phys_apicid_present (genapic->check_phys_apicid_present) #define check_phys_apicid_present (genapic->check_phys_apicid_present)
#define check_apicid_used (genapic->check_apicid_used) #define check_apicid_used (genapic->check_apicid_used)
#define GET_APIC_ID (genapic->get_apic_id)
#define APIC_ID_MASK (genapic->apic_id_mask)
#define cpu_mask_to_apicid (genapic->cpu_mask_to_apicid) #define cpu_mask_to_apicid (genapic->cpu_mask_to_apicid)
#endif /* __ASM_MACH_APIC_H */ #endif /* __ASM_MACH_APIC_H */
#ifndef _GENAPIC_MACH_APICDEF_H
#define _GENAPIC_MACH_APICDEF_H 1
#ifndef APIC_DEFINITION
#include <asm/genapic.h>
#define GET_APIC_ID (genapic->get_apic_id)
#define APIC_ID_MASK (genapic->apic_id_mask)
#endif
#endif
...@@ -73,4 +73,6 @@ struct stat64 { ...@@ -73,4 +73,6 @@ struct stat64 {
unsigned long long st_ino; unsigned long long st_ino;
}; };
#define STAT_HAVE_NSEC 1
#endif #endif
...@@ -209,6 +209,10 @@ ia64_phys_addr_valid (unsigned long addr) ...@@ -209,6 +209,10 @@ ia64_phys_addr_valid (unsigned long addr)
#define VMALLOC_VMADDR(x) ((unsigned long)(x)) #define VMALLOC_VMADDR(x) ((unsigned long)(x))
#define VMALLOC_END (0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9))) #define VMALLOC_END (0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9)))
/* fs/proc/kcore.c */
#define kc_vaddr_to_offset(v) ((v) - 0xA000000000000000)
#define kc_offset_to_vaddr(o) ((o) + 0xA000000000000000)
/* /*
* Conversion functions: convert page frame number (pfn) and a protection value to a page * Conversion functions: convert page frame number (pfn) and a protection value to a page
* table entry (pte). * table entry (pte).
......
...@@ -83,8 +83,6 @@ struct gendisk { ...@@ -83,8 +83,6 @@ struct gendisk {
int major; /* major number of driver */ int major; /* major number of driver */
int first_minor; int first_minor;
int minors; int minors;
int minor_shift; /* number of times minor is shifted to
get real minor */
char disk_name[16]; /* name of major driver */ char disk_name[16]; /* name of major driver */
struct hd_struct **part; /* [indexed by minor] */ struct hd_struct **part; /* [indexed by minor] */
struct block_device_operations *fops; struct block_device_operations *fops;
......
...@@ -45,7 +45,9 @@ ...@@ -45,7 +45,9 @@
#define INIT_SIGNALS(sig) { \ #define INIT_SIGNALS(sig) { \
.count = ATOMIC_INIT(1), \ .count = ATOMIC_INIT(1), \
.shared_pending = { NULL, &sig.shared_pending.head, {{0}}}, \ .shared_pending = { \
.list = LIST_HEAD_INIT(sig.shared_pending.list), \
.signal = {{0}}}, \
} }
#define INIT_SIGHAND(sighand) { \ #define INIT_SIGHAND(sighand) { \
...@@ -97,9 +99,11 @@ ...@@ -97,9 +99,11 @@
.files = &init_files, \ .files = &init_files, \
.signal = &init_signals, \ .signal = &init_signals, \
.sighand = &init_sighand, \ .sighand = &init_sighand, \
.pending = { NULL, &tsk.pending.head, {{0}}}, \ .pending = { \
.list = LIST_HEAD_INIT(tsk.pending.list), \
.signal = {{0}}}, \
.blocked = {{0}}, \ .blocked = {{0}}, \
.posix_timers = LIST_HEAD_INIT(tsk.posix_timers), \ .posix_timers = LIST_HEAD_INIT(tsk.posix_timers), \
.alloc_lock = SPIN_LOCK_UNLOCKED, \ .alloc_lock = SPIN_LOCK_UNLOCKED, \
.proc_lock = SPIN_LOCK_UNLOCKED, \ .proc_lock = SPIN_LOCK_UNLOCKED, \
.switch_lock = SPIN_LOCK_UNLOCKED, \ .switch_lock = SPIN_LOCK_UNLOCKED, \
......
...@@ -74,6 +74,12 @@ struct proc_dir_entry { ...@@ -74,6 +74,12 @@ struct proc_dir_entry {
kdev_t rdev; kdev_t rdev;
}; };
struct kcore_list {
struct kcore_list *next;
unsigned long addr;
size_t size;
};
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
extern struct proc_dir_entry proc_root; extern struct proc_dir_entry proc_root;
...@@ -179,6 +185,12 @@ static inline void proc_net_remove(const char *name) ...@@ -179,6 +185,12 @@ static inline void proc_net_remove(const char *name)
remove_proc_entry(name,proc_net); remove_proc_entry(name,proc_net);
} }
/*
* fs/proc/kcore.c
*/
extern void kclist_add(struct kcore_list *, void *, size_t);
extern struct kcore_list *kclist_del(void *);
#else #else
#define proc_root_driver NULL #define proc_root_driver NULL
...@@ -223,6 +235,8 @@ static inline struct kcore_list * kclist_del(void *addr) ...@@ -223,6 +235,8 @@ static inline struct kcore_list * kclist_del(void *addr)
return NULL; return NULL;
} }
static inline void kclist_add(struct kcore_list *new, void *addr, size_t size) {};
static inline struct kcore_list * kclist_del(void *addr) {return NULL};
#endif /* CONFIG_PROC_FS */ #endif /* CONFIG_PROC_FS */
struct proc_inode { struct proc_inode {
......
...@@ -317,6 +317,7 @@ struct k_itimer { ...@@ -317,6 +317,7 @@ struct k_itimer {
unsigned long it_incr; /* interval specified in jiffies */ unsigned long it_incr; /* interval specified in jiffies */
struct task_struct *it_process; /* process to send signal to */ struct task_struct *it_process; /* process to send signal to */
struct timer_list it_timer; struct timer_list it_timer;
struct sigqueue *sigq; /* signal queue entry. */
}; };
...@@ -571,6 +572,10 @@ extern void zap_other_threads(struct task_struct *p); ...@@ -571,6 +572,10 @@ extern void zap_other_threads(struct task_struct *p);
extern int kill_pg(pid_t, int, int); extern int kill_pg(pid_t, int, int);
extern int kill_sl(pid_t, int, int); extern int kill_sl(pid_t, int, int);
extern int kill_proc(pid_t, int, int); extern int kill_proc(pid_t, int, int);
extern struct sigqueue *sigqueue_alloc(void);
extern void sigqueue_free(struct sigqueue *);
extern int send_sigqueue(int, struct sigqueue *, struct task_struct *);
extern int send_group_sigqueue(int, struct sigqueue *, struct task_struct *);
extern int do_sigaction(int, const struct k_sigaction *, struct k_sigaction *); extern int do_sigaction(int, const struct k_sigaction *, struct k_sigaction *);
extern int do_sigaltstack(const stack_t __user *, stack_t __user *, unsigned long); extern int do_sigaltstack(const stack_t __user *, stack_t __user *, unsigned long);
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include <asm/signal.h> #include <asm/signal.h>
#include <asm/siginfo.h> #include <asm/siginfo.h>
#include <linux/list.h>
#ifdef __KERNEL__ #ifdef __KERNEL__
/* /*
...@@ -10,12 +11,17 @@ ...@@ -10,12 +11,17 @@
*/ */
struct sigqueue { struct sigqueue {
struct sigqueue *next; struct list_head list;
spinlock_t *lock;
int flags;
siginfo_t info; siginfo_t info;
}; };
/* flags values. */
#define SIGQUEUE_PREALLOC 1
struct sigpending { struct sigpending {
struct sigqueue *head, **tail; struct list_head list;
sigset_t signal; sigset_t signal;
}; };
...@@ -197,8 +203,7 @@ static inline void siginitsetinv(sigset_t *set, unsigned long mask) ...@@ -197,8 +203,7 @@ static inline void siginitsetinv(sigset_t *set, unsigned long mask)
static inline void init_sigpending(struct sigpending *sig) static inline void init_sigpending(struct sigpending *sig)
{ {
sigemptyset(&sig->signal); sigemptyset(&sig->signal);
sig->head = NULL; INIT_LIST_HEAD(&sig->list);
sig->tail = &sig->head;
} }
extern long do_sigpending(void __user *, unsigned long); extern long do_sigpending(void __user *, unsigned long);
......
...@@ -51,6 +51,9 @@ ...@@ -51,6 +51,9 @@
#ifndef _LINUX_TIMEX_H #ifndef _LINUX_TIMEX_H
#define _LINUX_TIMEX_H #define _LINUX_TIMEX_H
#include <linux/config.h>
#include <linux/compiler.h>
#include <asm/param.h> #include <asm/param.h>
/* /*
...@@ -310,6 +313,105 @@ extern long pps_calcnt; /* calibration intervals */ ...@@ -310,6 +313,105 @@ extern long pps_calcnt; /* calibration intervals */
extern long pps_errcnt; /* calibration errors */ extern long pps_errcnt; /* calibration errors */
extern long pps_stbcnt; /* stability limit exceeded */ extern long pps_stbcnt; /* stability limit exceeded */
#ifdef CONFIG_TIME_INTERPOLATION
struct time_interpolator {
/* cache-hot stuff first: */
unsigned long (*get_offset) (void);
void (*update) (long);
void (*reset) (void);
/* cache-cold stuff follows here: */
struct time_interpolator *next;
unsigned long frequency; /* frequency in counts/second */
long drift; /* drift in parts-per-million (or -1) */
};
extern volatile unsigned long last_nsec_offset;
#ifndef __HAVE_ARCH_CMPXCHG
extern spin_lock_t last_nsec_offset_lock;
#endif
extern struct time_interpolator *time_interpolator;
extern void register_time_interpolator(struct time_interpolator *);
extern void unregister_time_interpolator(struct time_interpolator *);
/* Called with xtime WRITE-lock acquired. */
static inline void
time_interpolator_update(long delta_nsec)
{
struct time_interpolator *ti = time_interpolator;
if (last_nsec_offset > 0) {
#ifdef __HAVE_ARCH_CMPXCHG
unsigned long new, old;
do {
old = last_nsec_offset;
if (old > delta_nsec)
new = old - delta_nsec;
else
new = 0;
} while (cmpxchg(&last_nsec_offset, old, new) != old);
#else
/*
* This really hurts, because it serializes gettimeofday(), but without an
* atomic single-word compare-and-exchange, there isn't all that much else
* we can do.
*/
spin_lock(&last_nsec_offset_lock);
{
last_nsec_offset -= min(last_nsec_offset, delta_nsec);
}
spin_unlock(&last_nsec_offset_lock);
#endif
}
if (ti)
(*ti->update)(delta_nsec);
}
/* Called with xtime WRITE-lock acquired. */
static inline void
time_interpolator_reset(void)
{
struct time_interpolator *ti = time_interpolator;
last_nsec_offset = 0;
if (ti)
(*ti->reset)();
}
/* Called with xtime READ-lock acquired. */
static inline unsigned long
time_interpolator_get_offset(void)
{
struct time_interpolator *ti = time_interpolator;
if (ti)
return (*ti->get_offset)();
return last_nsec_offset;
}
#else /* !CONFIG_TIME_INTERPOLATION */
static inline void
time_interpolator_update(long delta_nsec)
{
}
static inline void
time_interpolator_reset(void)
{
}
static inline unsigned long
time_interpolator_get_offset(void)
{
return 0;
}
#endif /* !CONFIG_TIME_INTERPOLATION */
#endif /* KERNEL */ #endif /* KERNEL */
#endif /* LINUX_TIMEX_H */ #endif /* LINUX_TIMEX_H */
...@@ -78,6 +78,10 @@ extern int vm_dirty_ratio; ...@@ -78,6 +78,10 @@ extern int vm_dirty_ratio;
extern int dirty_writeback_centisecs; extern int dirty_writeback_centisecs;
extern int dirty_expire_centisecs; extern int dirty_expire_centisecs;
struct ctl_table;
struct file;
int dirty_writeback_centisecs_handler(struct ctl_table *, int, struct file *,
void *, size_t *);
void page_writeback_init(void); void page_writeback_init(void);
void balance_dirty_pages(struct address_space *mapping); void balance_dirty_pages(struct address_space *mapping);
......
...@@ -268,39 +268,39 @@ static int try_atomic_semop (struct sem_array * sma, struct sembuf * sops, ...@@ -268,39 +268,39 @@ static int try_atomic_semop (struct sem_array * sma, struct sembuf * sops,
for (sop = sops; sop < sops + nsops; sop++) { for (sop = sops; sop < sops + nsops; sop++) {
curr = sma->sem_base + sop->sem_num; curr = sma->sem_base + sop->sem_num;
sem_op = sop->sem_op; sem_op = sop->sem_op;
result = curr->semval;
if (!sem_op && curr->semval)
if (!sem_op && result)
goto would_block; goto would_block;
curr->sempid = (curr->sempid << 16) | pid; result += sem_op;
curr->semval += sem_op; if (result < 0)
if (sop->sem_flg & SEM_UNDO) goto would_block;
{ if (result > SEMVMX)
goto out_of_range;
if (sop->sem_flg & SEM_UNDO) {
int undo = un->semadj[sop->sem_num] - sem_op; int undo = un->semadj[sop->sem_num] - sem_op;
/* /*
* Exceeding the undo range is an error. * Exceeding the undo range is an error.
*/ */
if (undo < (-SEMAEM - 1) || undo > SEMAEM) if (undo < (-SEMAEM - 1) || undo > SEMAEM)
{
/* Don't undo the undo */
sop->sem_flg &= ~SEM_UNDO;
goto out_of_range; goto out_of_range;
}
un->semadj[sop->sem_num] = undo;
} }
if (curr->semval < 0) curr->semval = result;
goto would_block;
if (curr->semval > SEMVMX)
goto out_of_range;
} }
if (do_undo) if (do_undo) {
{
sop--;
result = 0; result = 0;
goto undo; goto undo;
} }
sop--;
while (sop >= sops) {
sma->sem_base[sop->sem_num].sempid = pid;
if (sop->sem_flg & SEM_UNDO)
un->semadj[sop->sem_num] -= sop->sem_op;
sop--;
}
sma->sem_otime = get_seconds(); sma->sem_otime = get_seconds();
return 0; return 0;
...@@ -315,13 +315,9 @@ static int try_atomic_semop (struct sem_array * sma, struct sembuf * sops, ...@@ -315,13 +315,9 @@ static int try_atomic_semop (struct sem_array * sma, struct sembuf * sops,
result = 1; result = 1;
undo: undo:
sop--;
while (sop >= sops) { while (sop >= sops) {
curr = sma->sem_base + sop->sem_num; sma->sem_base[sop->sem_num].semval -= sop->sem_op;
curr->semval -= sop->sem_op;
curr->sempid >>= 16;
if (sop->sem_flg & SEM_UNDO)
un->semadj[sop->sem_num] += sop->sem_op;
sop--; sop--;
} }
...@@ -659,7 +655,7 @@ static int semctl_main(int semid, int semnum, int cmd, int version, union semun ...@@ -659,7 +655,7 @@ static int semctl_main(int semid, int semnum, int cmd, int version, union semun
err = curr->semval; err = curr->semval;
goto out_unlock; goto out_unlock;
case GETPID: case GETPID:
err = curr->sempid & 0xffff; err = curr->sempid;
goto out_unlock; goto out_unlock;
case GETNCNT: case GETNCNT:
err = count_semncnt(sma,semnum); err = count_semncnt(sma,semnum);
......
...@@ -288,46 +288,32 @@ void do_schedule_next_timer(struct siginfo *info) ...@@ -288,46 +288,32 @@ void do_schedule_next_timer(struct siginfo *info)
static void timer_notify_task(struct k_itimer *timr) static void timer_notify_task(struct k_itimer *timr)
{ {
struct siginfo info;
int ret; int ret;
memset(&info, 0, sizeof (info)); memset(&timr->sigq->info, 0, sizeof(siginfo_t));
/* Send signal to the process that owns this timer. */ /* Send signal to the process that owns this timer. */
info.si_signo = timr->it_sigev_signo; timr->sigq->info.si_signo = timr->it_sigev_signo;
info.si_errno = 0; timr->sigq->info.si_errno = 0;
info.si_code = SI_TIMER; timr->sigq->info.si_code = SI_TIMER;
info.si_tid = timr->it_id; timr->sigq->info.si_tid = timr->it_id;
info.si_value = timr->it_sigev_value; timr->sigq->info.si_value = timr->it_sigev_value;
if (timr->it_incr) if (timr->it_incr)
info.si_sys_private = ++timr->it_requeue_pending; timr->sigq->info.si_sys_private = ++timr->it_requeue_pending;
if (timr->it_sigev_notify & SIGEV_THREAD_ID & MIPS_SIGEV) if (timr->it_sigev_notify & SIGEV_THREAD_ID & MIPS_SIGEV)
ret = send_sig_info(info.si_signo, &info, timr->it_process); ret = send_sigqueue(timr->it_sigev_signo, timr->sigq,
timr->it_process);
else else
ret = send_group_sig_info(info.si_signo, &info, ret = send_group_sigqueue(timr->it_sigev_signo, timr->sigq,
timr->it_process); timr->it_process);
switch (ret) { if (ret) {
default:
/*
* Signal was not sent. May or may not need to
* restart the timer.
*/
printk(KERN_WARNING "sending signal failed: %d\n", ret);
case 1:
/* /*
* signal was not sent because of sig_ignor or, * signal was not sent because of sig_ignor
* possibly no queue memory OR will be sent but,
* we will not get a call back to restart it AND * we will not get a call back to restart it AND
* it should be restarted. * it should be restarted.
*/ */
schedule_next_timer(timr); schedule_next_timer(timr);
case 0:
/*
* all's well new signal queued
*/
break;
} }
} }
...@@ -379,7 +365,11 @@ static struct k_itimer * alloc_posix_timer(void) ...@@ -379,7 +365,11 @@ static struct k_itimer * alloc_posix_timer(void)
struct k_itimer *tmr; struct k_itimer *tmr;
tmr = kmem_cache_alloc(posix_timers_cache, GFP_KERNEL); tmr = kmem_cache_alloc(posix_timers_cache, GFP_KERNEL);
memset(tmr, 0, sizeof (struct k_itimer)); memset(tmr, 0, sizeof (struct k_itimer));
tmr->it_id = (timer_t)-1;
if (unlikely(!(tmr->sigq = sigqueue_alloc()))) {
kmem_cache_free(posix_timers_cache, tmr);
tmr = 0;
}
return tmr; return tmr;
} }
...@@ -390,6 +380,7 @@ static void release_posix_timer(struct k_itimer *tmr) ...@@ -390,6 +380,7 @@ static void release_posix_timer(struct k_itimer *tmr)
idr_remove(&posix_timers_id, tmr->it_id); idr_remove(&posix_timers_id, tmr->it_id);
spin_unlock_irq(&idr_lock); spin_unlock_irq(&idr_lock);
} }
sigqueue_free(tmr->sigq);
kmem_cache_free(posix_timers_cache, tmr); kmem_cache_free(posix_timers_cache, tmr);
} }
......
This diff is collapsed.
...@@ -271,7 +271,6 @@ static ctl_table kern_table[] = { ...@@ -271,7 +271,6 @@ static ctl_table kern_table[] = {
/* Constants for minimum and maximum testing in vm_table. /* Constants for minimum and maximum testing in vm_table.
We use these as one-element integer vectors. */ We use these as one-element integer vectors. */
static int zero = 0; static int zero = 0;
static int one = 1;
static int one_hundred = 100; static int one_hundred = 100;
...@@ -292,20 +291,7 @@ static ctl_table vm_table[] = { ...@@ -292,20 +291,7 @@ static ctl_table vm_table[] = {
&sysctl_intvec, NULL, &zero, &one_hundred }, &sysctl_intvec, NULL, &zero, &one_hundred },
{VM_DIRTY_WB_CS, "dirty_writeback_centisecs", {VM_DIRTY_WB_CS, "dirty_writeback_centisecs",
&dirty_writeback_centisecs, sizeof(dirty_writeback_centisecs), 0644, &dirty_writeback_centisecs, sizeof(dirty_writeback_centisecs), 0644,
NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL, NULL, dirty_writeback_centisecs_handler },
/* Here, we define the range of possible values for
dirty_writeback_centisecs.
The default value is 5 seconds (500 centisec). We will use 1
centisec, the smallest possible value that could make any sort of
sense. If we allowed the user to set the interval to 0 seconds
(which would presumably mean to chew up all of the CPU looking for
dirty pages and writing them out, without taking a break), the
interval would effectively become 1 second (100 centisecs), due to
some nicely documented throttling code in wb_kupdate().
There is no maximum legal value for dirty_writeback. */
&one , NULL},
{VM_DIRTY_EXPIRE_CS, "dirty_expire_centisecs", {VM_DIRTY_EXPIRE_CS, "dirty_expire_centisecs",
&dirty_expire_centisecs, sizeof(dirty_expire_centisecs), 0644, &dirty_expire_centisecs, sizeof(dirty_expire_centisecs), 0644,
NULL, &proc_dointvec}, NULL, &proc_dointvec},
......
...@@ -35,8 +35,6 @@ ...@@ -35,8 +35,6 @@
*/ */
struct timezone sys_tz; struct timezone sys_tz;
extern unsigned long last_time_offset;
#if !defined(__alpha__) && !defined(__ia64__) #if !defined(__alpha__) && !defined(__ia64__)
/* /*
...@@ -77,9 +75,10 @@ asmlinkage long sys_stime(int * tptr) ...@@ -77,9 +75,10 @@ asmlinkage long sys_stime(int * tptr)
if (get_user(value, tptr)) if (get_user(value, tptr))
return -EFAULT; return -EFAULT;
write_seqlock_irq(&xtime_lock); write_seqlock_irq(&xtime_lock);
time_interpolator_reset();
xtime.tv_sec = value; xtime.tv_sec = value;
xtime.tv_nsec = 0; xtime.tv_nsec = 0;
last_time_offset = 0;
time_adjust = 0; /* stop active adjtime() */ time_adjust = 0; /* stop active adjtime() */
time_status |= STA_UNSYNC; time_status |= STA_UNSYNC;
time_maxerror = NTP_PHASE_LIMIT; time_maxerror = NTP_PHASE_LIMIT;
...@@ -125,7 +124,7 @@ inline static void warp_clock(void) ...@@ -125,7 +124,7 @@ inline static void warp_clock(void)
{ {
write_seqlock_irq(&xtime_lock); write_seqlock_irq(&xtime_lock);
xtime.tv_sec += sys_tz.tz_minuteswest * 60; xtime.tv_sec += sys_tz.tz_minuteswest * 60;
last_time_offset = 0; time_interpolator_update(sys_tz.tz_minuteswest * 60 * NSEC_PER_SEC);
write_sequnlock_irq(&xtime_lock); write_sequnlock_irq(&xtime_lock);
} }
...@@ -381,7 +380,6 @@ leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0 ...@@ -381,7 +380,6 @@ leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0
txc->calcnt = pps_calcnt; txc->calcnt = pps_calcnt;
txc->errcnt = pps_errcnt; txc->errcnt = pps_errcnt;
txc->stbcnt = pps_stbcnt; txc->stbcnt = pps_stbcnt;
last_time_offset = 0;
write_sequnlock_irq(&xtime_lock); write_sequnlock_irq(&xtime_lock);
do_gettimeofday(&txc->time); do_gettimeofday(&txc->time);
return(result); return(result);
......
...@@ -517,6 +517,7 @@ static void second_overflow(void) ...@@ -517,6 +517,7 @@ static void second_overflow(void)
if (xtime.tv_sec % 86400 == 0) { if (xtime.tv_sec % 86400 == 0) {
xtime.tv_sec--; xtime.tv_sec--;
wall_to_monotonic.tv_sec++; wall_to_monotonic.tv_sec++;
time_interpolator_update(-NSEC_PER_SEC);
time_state = TIME_OOP; time_state = TIME_OOP;
clock_was_set(); clock_was_set();
printk(KERN_NOTICE "Clock: inserting leap second 23:59:60 UTC\n"); printk(KERN_NOTICE "Clock: inserting leap second 23:59:60 UTC\n");
...@@ -527,6 +528,7 @@ static void second_overflow(void) ...@@ -527,6 +528,7 @@ static void second_overflow(void)
if ((xtime.tv_sec + 1) % 86400 == 0) { if ((xtime.tv_sec + 1) % 86400 == 0) {
xtime.tv_sec++; xtime.tv_sec++;
wall_to_monotonic.tv_sec--; wall_to_monotonic.tv_sec--;
time_interpolator_update(NSEC_PER_SEC);
time_state = TIME_WAIT; time_state = TIME_WAIT;
clock_was_set(); clock_was_set();
printk(KERN_NOTICE "Clock: deleting leap second 23:59:59 UTC\n"); printk(KERN_NOTICE "Clock: deleting leap second 23:59:59 UTC\n");
...@@ -605,7 +607,7 @@ static void second_overflow(void) ...@@ -605,7 +607,7 @@ static void second_overflow(void)
/* in the NTP reference this is called "hardclock()" */ /* in the NTP reference this is called "hardclock()" */
static void update_wall_time_one_tick(void) static void update_wall_time_one_tick(void)
{ {
long time_adjust_step; long time_adjust_step, delta_nsec;
if ( (time_adjust_step = time_adjust) != 0 ) { if ( (time_adjust_step = time_adjust) != 0 ) {
/* We are doing an adjtime thing. /* We are doing an adjtime thing.
...@@ -621,11 +623,11 @@ static void update_wall_time_one_tick(void) ...@@ -621,11 +623,11 @@ static void update_wall_time_one_tick(void)
time_adjust_step = tickadj; time_adjust_step = tickadj;
else if (time_adjust < -tickadj) else if (time_adjust < -tickadj)
time_adjust_step = -tickadj; time_adjust_step = -tickadj;
/* Reduce by this step the amount of time left */ /* Reduce by this step the amount of time left */
time_adjust -= time_adjust_step; time_adjust -= time_adjust_step;
} }
xtime.tv_nsec += tick_nsec + time_adjust_step * 1000; delta_nsec = tick_nsec + time_adjust_step * 1000;
/* /*
* Advance the phase, once it gets to one microsecond, then * Advance the phase, once it gets to one microsecond, then
* advance the tick more. * advance the tick more.
...@@ -634,13 +636,15 @@ static void update_wall_time_one_tick(void) ...@@ -634,13 +636,15 @@ static void update_wall_time_one_tick(void)
if (time_phase <= -FINEUSEC) { if (time_phase <= -FINEUSEC) {
long ltemp = -time_phase >> (SHIFT_SCALE - 10); long ltemp = -time_phase >> (SHIFT_SCALE - 10);
time_phase += ltemp << (SHIFT_SCALE - 10); time_phase += ltemp << (SHIFT_SCALE - 10);
xtime.tv_nsec -= ltemp; delta_nsec -= ltemp;
} }
else if (time_phase >= FINEUSEC) { else if (time_phase >= FINEUSEC) {
long ltemp = time_phase >> (SHIFT_SCALE - 10); long ltemp = time_phase >> (SHIFT_SCALE - 10);
time_phase -= ltemp << (SHIFT_SCALE - 10); time_phase -= ltemp << (SHIFT_SCALE - 10);
xtime.tv_nsec += ltemp; delta_nsec += ltemp;
} }
xtime.tv_nsec += delta_nsec;
time_interpolator_update(delta_nsec);
} }
/* /*
...@@ -660,6 +664,7 @@ static void update_wall_time(unsigned long ticks) ...@@ -660,6 +664,7 @@ static void update_wall_time(unsigned long ticks)
if (xtime.tv_nsec >= 1000000000) { if (xtime.tv_nsec >= 1000000000) {
xtime.tv_nsec -= 1000000000; xtime.tv_nsec -= 1000000000;
xtime.tv_sec++; xtime.tv_sec++;
time_interpolator_update(NSEC_PER_SEC);
second_overflow(); second_overflow();
} }
} }
...@@ -777,7 +782,6 @@ unsigned long wall_jiffies = INITIAL_JIFFIES; ...@@ -777,7 +782,6 @@ unsigned long wall_jiffies = INITIAL_JIFFIES;
#ifndef ARCH_HAVE_XTIME_LOCK #ifndef ARCH_HAVE_XTIME_LOCK
seqlock_t xtime_lock __cacheline_aligned_in_smp = SEQLOCK_UNLOCKED; seqlock_t xtime_lock __cacheline_aligned_in_smp = SEQLOCK_UNLOCKED;
#endif #endif
unsigned long last_time_offset;
/* /*
* This function runs timers and the timer-tq in bottom half context. * This function runs timers and the timer-tq in bottom half context.
...@@ -811,7 +815,6 @@ static inline void update_times(void) ...@@ -811,7 +815,6 @@ static inline void update_times(void)
wall_jiffies += ticks; wall_jiffies += ticks;
update_wall_time(ticks); update_wall_time(ticks);
} }
last_time_offset = 0;
calc_load(ticks); calc_load(ticks);
} }
...@@ -1221,3 +1224,80 @@ void __init init_timers(void) ...@@ -1221,3 +1224,80 @@ void __init init_timers(void)
register_cpu_notifier(&timers_nb); register_cpu_notifier(&timers_nb);
open_softirq(TIMER_SOFTIRQ, run_timer_softirq, NULL); open_softirq(TIMER_SOFTIRQ, run_timer_softirq, NULL);
} }
#ifdef CONFIG_TIME_INTERPOLATION
volatile unsigned long last_nsec_offset;
struct time_interpolator *time_interpolator;
#ifndef __HAVE_ARCH_CMPXCHG
spinlock_t last_nsec_offset_lock = SPIN_LOCK_UNLOCKED;
#endif
static struct {
spinlock_t lock; /* lock protecting list */
struct time_interpolator *list; /* list of registered interpolators */
} ti_global = {
.lock = SPIN_LOCK_UNLOCKED
};
static inline int
is_better_time_interpolator(struct time_interpolator *new)
{
if (!time_interpolator)
return 1;
return new->frequency > 2*time_interpolator->frequency
|| (unsigned long) new->drift < (unsigned long) time_interpolator->drift;
}
void
register_time_interpolator(struct time_interpolator *ti)
{
spin_lock(&ti_global.lock);
{
write_seqlock_irq(&xtime_lock);
{
if (is_better_time_interpolator(ti))
time_interpolator = ti;
}
write_sequnlock_irq(&xtime_lock);
ti->next = ti_global.list;
ti_global.list = ti;
}
spin_unlock(&ti_global.lock);
}
void
unregister_time_interpolator(struct time_interpolator *ti)
{
struct time_interpolator *curr, **prev;
spin_lock(&ti_global.lock);
{
prev = &ti_global.list;
for (curr = *prev; curr; curr = curr->next) {
if (curr == ti) {
*prev = curr->next;
break;
}
prev = &curr->next;
}
write_seqlock_irq(&xtime_lock);
{
if (ti == time_interpolator) {
/* we lost the best time-interpolator: */
time_interpolator = NULL;
/* find the next-best interpolator */
for (curr = ti_global.list; curr; curr = curr->next)
if (is_better_time_interpolator(curr))
time_interpolator = curr;
}
}
write_sequnlock_irq(&xtime_lock);
}
spin_unlock(&ti_global.lock);
}
#endif /* CONFIG_TIME_INTERPOLATION */
...@@ -677,6 +677,7 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, ...@@ -677,6 +677,7 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
vma->vm_pgoff = pgoff; vma->vm_pgoff = pgoff;
vma->vm_file = NULL; vma->vm_file = NULL;
vma->vm_private_data = NULL; vma->vm_private_data = NULL;
vma->vm_next = NULL;
INIT_LIST_HEAD(&vma->shared); INIT_LIST_HEAD(&vma->shared);
if (file) { if (file) {
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/percpu.h> #include <linux/percpu.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/sysctl.h>
/* /*
* The maximum number of pages to writeout in a single bdflush/kupdate * The maximum number of pages to writeout in a single bdflush/kupdate
...@@ -329,7 +330,24 @@ static void wb_kupdate(unsigned long arg) ...@@ -329,7 +330,24 @@ static void wb_kupdate(unsigned long arg)
} }
if (time_before(next_jif, jiffies + HZ)) if (time_before(next_jif, jiffies + HZ))
next_jif = jiffies + HZ; next_jif = jiffies + HZ;
mod_timer(&wb_timer, next_jif); if (dirty_writeback_centisecs)
mod_timer(&wb_timer, next_jif);
}
/*
* sysctl handler for /proc/sys/vm/dirty_writeback_centisecs
*/
int dirty_writeback_centisecs_handler(ctl_table *table, int write,
struct file *file, void *buffer, size_t *length)
{
proc_dointvec(table, write, file, buffer, length);
if (dirty_writeback_centisecs) {
mod_timer(&wb_timer,
jiffies + (dirty_writeback_centisecs * HZ) / 100);
} else {
del_timer(&wb_timer);
}
return 0;
} }
static void wb_timer_fn(unsigned long unused) static void wb_timer_fn(unsigned long unused)
......
This diff is collapsed.
...@@ -35,44 +35,6 @@ static struct menu *rootEntry; ...@@ -35,44 +35,6 @@ static struct menu *rootEntry;
static char nohelp_text[] = "Sorry, no help available for this option yet.\n"; static char nohelp_text[] = "Sorry, no help available for this option yet.\n";
#if 0
static void printc(int ch)
{
static int sep = 0;
if (!sep) {
putchar('[');
sep = 1;
} else if (ch)
putchar('/');
if (!ch) {
putchar(']');
putchar(' ');
sep = 0;
} else
putchar(ch);
}
#endif
static void printo(const char *o)
{
static int sep = 0;
if (!sep) {
putchar('(');
sep = 1;
} else if (o) {
putchar(',');
putchar(' ');
}
if (!o) {
putchar(')');
putchar(' ');
sep = 0;
} else
printf("%s", o);
}
static void strip(char *str) static void strip(char *str)
{ {
char *p = str; char *p = str;
...@@ -90,6 +52,16 @@ static void strip(char *str) ...@@ -90,6 +52,16 @@ static void strip(char *str)
*p-- = 0; *p-- = 0;
} }
static void check_stdin(void)
{
if (!valid_stdin && input_mode == ask_silent) {
printf("aborted!\n\n");
printf("Console input/output is redirected. ");
printf("Run 'make oldconfig' to update configuration.\n\n");
exit(1);
}
}
static void conf_askvalue(struct symbol *sym, const char *def) static void conf_askvalue(struct symbol *sym, const char *def)
{ {
enum symbol_type type = sym_get_type(sym); enum symbol_type type = sym_get_type(sym);
...@@ -108,13 +80,14 @@ static void conf_askvalue(struct symbol *sym, const char *def) ...@@ -108,13 +80,14 @@ static void conf_askvalue(struct symbol *sym, const char *def)
printf("%s\n", def); printf("%s\n", def);
return; return;
} }
if (!valid_stdin && input_mode == ask_silent) { check_stdin();
printf("aborted!\n\n");
printf("Console input/output is redirected. ");
printf("Run 'make oldconfig' to update configuration.\n\n");
exit(1);
}
case ask_all: case ask_all:
if (!sym_is_changable(sym)) {
printf("%s\n", def);
line[0] = '\n';
line[1] = 0;
return;
}
fflush(stdout); fflush(stdout);
fgets(line, 128, stdin); fgets(line, 128, stdin);
return; return;
...@@ -294,9 +267,8 @@ static int conf_sym(struct menu *menu) ...@@ -294,9 +267,8 @@ static int conf_sym(struct menu *menu)
static int conf_choice(struct menu *menu) static int conf_choice(struct menu *menu)
{ {
struct symbol *sym, *def_sym; struct symbol *sym, *def_sym;
struct menu *cmenu, *def_menu; struct menu *child;
const char *help; int type;
int type, len;
bool is_new; bool is_new;
sym = menu->sym; sym = menu->sym;
...@@ -314,74 +286,107 @@ static int conf_choice(struct menu *menu) ...@@ -314,74 +286,107 @@ static int conf_choice(struct menu *menu)
break; break;
} }
} else { } else {
sym->def = sym->curr; sym->user = sym->curr;
if (S_TRI(sym->curr) == mod) { if (sym->curr.tri == mod) {
printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu)); printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
return 0; return 0;
} }
} }
while (1) { while (1) {
printf("%*s%s ", indent - 1, "", menu_get_prompt(menu)); int cnt, def;
printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
def_sym = sym_get_choice_value(sym); def_sym = sym_get_choice_value(sym);
def_menu = NULL; cnt = def = 0;
for (cmenu = menu->list; cmenu; cmenu = cmenu->next) { line[0] = '0';
if (!menu_is_visible(cmenu)) line[1] = 0;
for (child = menu->list; child; child = child->next) {
if (!menu_is_visible(child))
continue; continue;
printo(menu_get_prompt(cmenu)); if (!child->sym) {
if (cmenu->sym == def_sym) printf("%*c %s\n", indent, '*', menu_get_prompt(child));
def_menu = cmenu; continue;
} }
printo(NULL); cnt++;
if (def_menu) if (child->sym == def_sym) {
printf("[%s] ", menu_get_prompt(def_menu)); def = cnt;
else { printf("%*c", indent, '>');
} else
printf("%*c", indent, ' ');
printf(" %d. %s", cnt, menu_get_prompt(child));
if (child->sym->name)
printf(" (%s)", child->sym->name);
if (!sym_has_value(child->sym))
printf(" (NEW)");
printf("\n"); printf("\n");
return 1;
} }
printf("%*schoice", indent - 1, "");
if (cnt == 1) {
printf("[1]: 1\n");
goto conf_childs;
}
printf("[1-%d", cnt);
if (sym->help)
printf("?");
printf("]: ");
switch (input_mode) { switch (input_mode) {
case ask_new: case ask_new:
case ask_silent: case ask_silent:
if (!is_new) {
cnt = def;
printf("%d\n", cnt);
break;
}
check_stdin();
case ask_all: case ask_all:
if (is_new) fflush(stdout);
sym->flags |= SYMBOL_NEW; fgets(line, 128, stdin);
conf_askvalue(sym, menu_get_prompt(def_menu));
strip(line); strip(line);
if (line[0] == '?') {
printf("\n%s\n", menu->sym->help ?
menu->sym->help : nohelp_text);
continue;
}
if (!line[0])
cnt = def;
else if (isdigit(line[0]))
cnt = atoi(line);
else
continue;
break;
case set_random:
def = (random() % cnt) + 1;
case set_default:
case set_yes:
case set_mod:
case set_no:
cnt = def;
printf("%d\n", cnt);
break; break;
default:
line[0] = 0;
printf("\n");
} }
if (line[0] == '?' && !line[1]) {
help = nohelp_text; conf_childs:
if (menu->sym->help) for (child = menu->list; child; child = child->next) {
help = menu->sym->help; if (!child->sym || !menu_is_visible(child))
printf("\n%s\n", help); continue;
continue; if (!--cnt)
break;
} }
if (line[0]) { if (!child)
len = strlen(line); continue;
line[len] = 0; if (line[strlen(line) - 1] == '?') {
printf("\n%s\n", child->sym->help ?
def_menu = NULL; child->sym->help : nohelp_text);
for (cmenu = menu->list; cmenu; cmenu = cmenu->next) { continue;
if (!cmenu->sym || !menu_is_visible(cmenu))
continue;
if (!strncasecmp(line, menu_get_prompt(cmenu), len)) {
def_menu = cmenu;
break;
}
}
} }
if (def_menu) { sym_set_choice_value(sym, child->sym);
sym_set_choice_value(sym, def_menu->sym); if (child->list) {
if (def_menu->list) { indent += 2;
indent += 2; conf(child->list);
conf(def_menu->list); indent -= 2;
indent -= 2;
}
return 1;
} }
return 1;
} }
} }
...@@ -422,7 +427,7 @@ static void conf(struct menu *menu) ...@@ -422,7 +427,7 @@ static void conf(struct menu *menu)
if (sym_is_choice(sym)) { if (sym_is_choice(sym)) {
conf_choice(menu); conf_choice(menu);
if (S_TRI(sym->curr) != mod) if (sym->curr.tri != mod)
return; return;
goto conf_childs; goto conf_childs;
} }
......
...@@ -105,11 +105,11 @@ int conf_read(const char *name) ...@@ -105,11 +105,11 @@ int conf_read(const char *name)
case S_INT: case S_INT:
case S_HEX: case S_HEX:
case S_STRING: case S_STRING:
if (S_VAL(sym->def)) if (sym->user.val)
free(S_VAL(sym->def)); free(sym->user.val);
default: default:
S_VAL(sym->def) = NULL; sym->user.val = NULL;
S_TRI(sym->def) = no; sym->user.tri = no;
} }
} }
...@@ -129,7 +129,7 @@ int conf_read(const char *name) ...@@ -129,7 +129,7 @@ int conf_read(const char *name)
switch (sym->type) { switch (sym->type) {
case S_BOOLEAN: case S_BOOLEAN:
case S_TRISTATE: case S_TRISTATE:
sym->def = symbol_no.curr; sym->user = symbol_no.curr;
sym->flags &= ~SYMBOL_NEW; sym->flags &= ~SYMBOL_NEW;
break; break;
default: default:
...@@ -154,18 +154,18 @@ int conf_read(const char *name) ...@@ -154,18 +154,18 @@ int conf_read(const char *name)
switch (sym->type) { switch (sym->type) {
case S_TRISTATE: case S_TRISTATE:
if (p[0] == 'm') { if (p[0] == 'm') {
S_TRI(sym->def) = mod; sym->user.tri = mod;
sym->flags &= ~SYMBOL_NEW; sym->flags &= ~SYMBOL_NEW;
break; break;
} }
case S_BOOLEAN: case S_BOOLEAN:
if (p[0] == 'y') { if (p[0] == 'y') {
S_TRI(sym->def) = yes; sym->user.tri = yes;
sym->flags &= ~SYMBOL_NEW; sym->flags &= ~SYMBOL_NEW;
break; break;
} }
if (p[0] == 'n') { if (p[0] == 'n') {
S_TRI(sym->def) = no; sym->user.tri = no;
sym->flags &= ~SYMBOL_NEW; sym->flags &= ~SYMBOL_NEW;
break; break;
} }
...@@ -187,7 +187,7 @@ int conf_read(const char *name) ...@@ -187,7 +187,7 @@ int conf_read(const char *name)
case S_INT: case S_INT:
case S_HEX: case S_HEX:
if (sym_string_valid(sym, p)) { if (sym_string_valid(sym, p)) {
S_VAL(sym->def) = strdup(p); sym->user.val = strdup(p);
sym->flags &= ~SYMBOL_NEW; sym->flags &= ~SYMBOL_NEW;
} else { } else {
fprintf(stderr, "%s:%d: symbol value '%s' invalid for %s\n", name, lineno, p, sym->name); fprintf(stderr, "%s:%d: symbol value '%s' invalid for %s\n", name, lineno, p, sym->name);
...@@ -198,21 +198,21 @@ int conf_read(const char *name) ...@@ -198,21 +198,21 @@ int conf_read(const char *name)
; ;
} }
if (sym_is_choice_value(sym)) { if (sym_is_choice_value(sym)) {
prop = sym_get_choice_prop(sym); struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
switch (S_TRI(sym->def)) { switch (sym->user.tri) {
case mod: case mod:
if (S_TRI(prop->def->def) == yes) if (cs->user.tri == yes)
/* warn? */; /* warn? */;
break; break;
case yes: case yes:
if (S_TRI(prop->def->def) != no) if (cs->user.tri != no)
/* warn? */; /* warn? */;
S_VAL(prop->def->def) = sym; cs->user.val = sym;
break; break;
case no: case no:
break; break;
} }
S_TRI(prop->def->def) = S_TRI(sym->def); cs->user.tri = sym->user.tri;
} }
break; break;
case '\n': case '\n':
...@@ -224,11 +224,25 @@ int conf_read(const char *name) ...@@ -224,11 +224,25 @@ int conf_read(const char *name)
fclose(in); fclose(in);
for_all_symbols(i, sym) { for_all_symbols(i, sym) {
sym_calc_value(sym);
if (sym_has_value(sym)) {
if (sym->visible == no)
sym->flags |= SYMBOL_NEW;
switch (sym->type) {
case S_STRING:
case S_INT:
case S_HEX:
if (!sym_string_within_range(sym, sym->user.val))
sym->flags |= SYMBOL_NEW;
default:
break;
}
}
if (!sym_is_choice(sym)) if (!sym_is_choice(sym))
continue; continue;
prop = sym_get_choice_prop(sym); prop = sym_get_choice_prop(sym);
sym->flags &= ~SYMBOL_NEW; sym->flags &= ~SYMBOL_NEW;
for (e = prop->dep; e; e = e->left.expr) for (e = prop->expr; e; e = e->left.expr)
sym->flags |= e->right.sym->flags & SYMBOL_NEW; sym->flags |= e->right.sym->flags & SYMBOL_NEW;
} }
...@@ -242,23 +256,45 @@ int conf_write(const char *name) ...@@ -242,23 +256,45 @@ int conf_write(const char *name)
FILE *out, *out_h; FILE *out, *out_h;
struct symbol *sym; struct symbol *sym;
struct menu *menu; struct menu *menu;
char oldname[128]; const char *basename;
char dirname[128], tmpname[128], newname[128];
int type, l; int type, l;
const char *str; const char *str;
out = fopen(".tmpconfig", "w"); dirname[0] = 0;
if (name && name[0]) {
char *slash = strrchr(name, '/');
if (slash) {
int size = slash - name + 1;
memcpy(dirname, name, size);
dirname[size] = 0;
if (slash[1])
basename = slash + 1;
else
basename = conf_def_filename;
} else
basename = name;
} else
basename = conf_def_filename;
sprintf(newname, "%s.tmpconfig.%d", dirname, getpid());
out = fopen(newname, "w");
if (!out) if (!out)
return 1; return 1;
out_h = fopen(".tmpconfig.h", "w"); out_h = NULL;
if (!out_h) if (!name) {
return 1; out_h = fopen(".tmpconfig.h", "w");
if (!out_h)
return 1;
}
fprintf(out, "#\n" fprintf(out, "#\n"
"# Automatically generated make config: don't edit\n" "# Automatically generated make config: don't edit\n"
"#\n"); "#\n");
fprintf(out_h, "/*\n" if (out_h)
" * Automatically generated C config: don't edit\n" fprintf(out_h, "/*\n"
" */\n" " * Automatically generated C config: don't edit\n"
"#define AUTOCONF_INCLUDED\n"); " */\n"
"#define AUTOCONF_INCLUDED\n");
if (!sym_change_count) if (!sym_change_count)
sym_clear_all_valid(); sym_clear_all_valid();
...@@ -274,10 +310,11 @@ int conf_write(const char *name) ...@@ -274,10 +310,11 @@ int conf_write(const char *name)
"#\n" "#\n"
"# %s\n" "# %s\n"
"#\n", str); "#\n", str);
fprintf(out_h, "\n" if (out_h)
"/*\n" fprintf(out_h, "\n"
" * %s\n" "/*\n"
" */\n", str); " * %s\n"
" */\n", str);
} else if (!(sym->flags & SYMBOL_CHOICE)) { } else if (!(sym->flags & SYMBOL_CHOICE)) {
sym_calc_value(sym); sym_calc_value(sym);
if (!(sym->flags & SYMBOL_WRITE)) if (!(sym->flags & SYMBOL_WRITE))
...@@ -286,7 +323,7 @@ int conf_write(const char *name) ...@@ -286,7 +323,7 @@ int conf_write(const char *name)
type = sym->type; type = sym->type;
if (type == S_TRISTATE) { if (type == S_TRISTATE) {
sym_calc_value(modules_sym); sym_calc_value(modules_sym);
if (S_TRI(modules_sym->curr) == no) if (modules_sym->curr.tri == no)
type = S_BOOLEAN; type = S_BOOLEAN;
} }
switch (type) { switch (type) {
...@@ -295,15 +332,18 @@ int conf_write(const char *name) ...@@ -295,15 +332,18 @@ int conf_write(const char *name)
switch (sym_get_tristate_value(sym)) { switch (sym_get_tristate_value(sym)) {
case no: case no:
fprintf(out, "# CONFIG_%s is not set\n", sym->name); fprintf(out, "# CONFIG_%s is not set\n", sym->name);
fprintf(out_h, "#undef CONFIG_%s\n", sym->name); if (out_h)
fprintf(out_h, "#undef CONFIG_%s\n", sym->name);
break; break;
case mod: case mod:
fprintf(out, "CONFIG_%s=m\n", sym->name); fprintf(out, "CONFIG_%s=m\n", sym->name);
fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name); if (out_h)
fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name);
break; break;
case yes: case yes:
fprintf(out, "CONFIG_%s=y\n", sym->name); fprintf(out, "CONFIG_%s=y\n", sym->name);
fprintf(out_h, "#define CONFIG_%s 1\n", sym->name); if (out_h)
fprintf(out_h, "#define CONFIG_%s 1\n", sym->name);
break; break;
} }
break; break;
...@@ -311,34 +351,40 @@ int conf_write(const char *name) ...@@ -311,34 +351,40 @@ int conf_write(const char *name)
// fix me // fix me
str = sym_get_string_value(sym); str = sym_get_string_value(sym);
fprintf(out, "CONFIG_%s=\"", sym->name); fprintf(out, "CONFIG_%s=\"", sym->name);
fprintf(out_h, "#define CONFIG_%s \"", sym->name); if (out_h)
fprintf(out_h, "#define CONFIG_%s \"", sym->name);
do { do {
l = strcspn(str, "\"\\"); l = strcspn(str, "\"\\");
if (l) { if (l) {
fwrite(str, l, 1, out); fwrite(str, l, 1, out);
fwrite(str, l, 1, out_h); if (out_h)
fwrite(str, l, 1, out_h);
} }
str += l; str += l;
while (*str == '\\' || *str == '"') { while (*str == '\\' || *str == '"') {
fprintf(out, "\\%c", *str); fprintf(out, "\\%c", *str);
fprintf(out_h, "\\%c", *str); if (out_h)
fprintf(out_h, "\\%c", *str);
str++; str++;
} }
} while (*str); } while (*str);
fputs("\"\n", out); fputs("\"\n", out);
fputs("\"\n", out_h); if (out_h)
fputs("\"\n", out_h);
break; break;
case S_HEX: case S_HEX:
str = sym_get_string_value(sym); str = sym_get_string_value(sym);
if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) { if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
fprintf(out, "CONFIG_%s=%s\n", sym->name, str); fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str); if (out_h)
fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str);
break; break;
} }
case S_INT: case S_INT:
str = sym_get_string_value(sym); str = sym_get_string_value(sym);
fprintf(out, "CONFIG_%s=%s\n", sym->name, str); fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str); if (out_h)
fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str);
break; break;
} }
} }
...@@ -358,18 +404,18 @@ int conf_write(const char *name) ...@@ -358,18 +404,18 @@ int conf_write(const char *name)
} }
} }
fclose(out); fclose(out);
fclose(out_h); if (out_h) {
fclose(out_h);
if (!name) {
rename(".tmpconfig.h", "include/linux/autoconf.h"); rename(".tmpconfig.h", "include/linux/autoconf.h");
name = conf_def_filename; }
file_write_dep(NULL); if (!name || basename != conf_def_filename) {
} else if (!name)
unlink(".tmpconfig.h"); name = conf_def_filename;
sprintf(tmpname, "%s.old", name);
sprintf(oldname, "%s.old", name); rename(name, tmpname);
rename(name, oldname); }
if (rename(".tmpconfig", name)) sprintf(tmpname, "%s%s", dirname, basename);
if (rename(newname, tmpname))
return 1; return 1;
sym_change_count = 0; sym_change_count = 0;
......
...@@ -55,6 +55,13 @@ struct expr *expr_alloc_and(struct expr *e1, struct expr *e2) ...@@ -55,6 +55,13 @@ struct expr *expr_alloc_and(struct expr *e1, struct expr *e2)
return e2 ? expr_alloc_two(E_AND, e1, e2) : e1; return e2 ? expr_alloc_two(E_AND, e1, e2) : e1;
} }
struct expr *expr_alloc_or(struct expr *e1, struct expr *e2)
{
if (!e1)
return e2;
return e2 ? expr_alloc_two(E_OR, e1, e2) : e1;
}
struct expr *expr_copy(struct expr *org) struct expr *expr_copy(struct expr *org)
{ {
struct expr *e; struct expr *e;
...@@ -158,9 +165,22 @@ static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct e ...@@ -158,9 +165,22 @@ static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct e
void expr_eliminate_eq(struct expr **ep1, struct expr **ep2) void expr_eliminate_eq(struct expr **ep1, struct expr **ep2)
{ {
if (!e1 || !e2 || e1->type != e2->type) if (!e1 || !e2)
return; return;
__expr_eliminate_eq(e1->type, ep1, ep2); switch (e1->type) {
case E_OR:
case E_AND:
__expr_eliminate_eq(e1->type, ep1, ep2);
default:
;
}
if (e1->type != e2->type) switch (e2->type) {
case E_OR:
case E_AND:
__expr_eliminate_eq(e2->type, ep1, ep2);
default:
;
}
e1 = expr_eliminate_yn(e1); e1 = expr_eliminate_yn(e1);
e2 = expr_eliminate_yn(e2); e2 = expr_eliminate_yn(e2);
} }
...@@ -195,6 +215,7 @@ int expr_eq(struct expr *e1, struct expr *e2) ...@@ -195,6 +215,7 @@ int expr_eq(struct expr *e1, struct expr *e2)
trans_count = old_count; trans_count = old_count;
return res; return res;
case E_CHOICE: case E_CHOICE:
case E_RANGE:
case E_NONE: case E_NONE:
/* panic */; /* panic */;
} }
...@@ -897,6 +918,7 @@ struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symb ...@@ -897,6 +918,7 @@ struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symb
case E_SYMBOL: case E_SYMBOL:
return expr_alloc_comp(type, e->left.sym, sym); return expr_alloc_comp(type, e->left.sym, sym);
case E_CHOICE: case E_CHOICE:
case E_RANGE:
case E_NONE: case E_NONE:
/* panic */; /* panic */;
} }
...@@ -914,7 +936,7 @@ tristate expr_calc_value(struct expr *e) ...@@ -914,7 +936,7 @@ tristate expr_calc_value(struct expr *e)
switch (e->type) { switch (e->type) {
case E_SYMBOL: case E_SYMBOL:
sym_calc_value(e->left.sym); sym_calc_value(e->left.sym);
return S_TRI(e->left.sym->curr); return e->left.sym->curr.tri;
case E_AND: case E_AND:
val1 = expr_calc_value(e->left.expr); val1 = expr_calc_value(e->left.expr);
val2 = expr_calc_value(e->right.expr); val2 = expr_calc_value(e->right.expr);
...@@ -1017,11 +1039,18 @@ void expr_print(struct expr *e, void (*fn)(void *, const char *), void *data, in ...@@ -1017,11 +1039,18 @@ void expr_print(struct expr *e, void (*fn)(void *, const char *), void *data, in
expr_print(e->right.expr, fn, data, E_AND); expr_print(e->right.expr, fn, data, E_AND);
break; break;
case E_CHOICE: case E_CHOICE:
fn(data, e->right.sym->name);
if (e->left.expr) { if (e->left.expr) {
expr_print(e->left.expr, fn, data, E_CHOICE);
fn(data, " ^ "); fn(data, " ^ ");
expr_print(e->left.expr, fn, data, E_CHOICE);
} }
break;
case E_RANGE:
fn(data, "[");
fn(data, e->left.sym->name);
fn(data, " ");
fn(data, e->right.sym->name); fn(data, e->right.sym->name);
fn(data, "]");
break; break;
default: default:
{ {
......
...@@ -18,10 +18,6 @@ extern "C" { ...@@ -18,10 +18,6 @@ extern "C" {
struct file { struct file {
struct file *next; struct file *next;
struct file *parent; struct file *parent;
#ifdef CML1
struct statement *stmt;
struct statement *last_stmt;
#endif
char *name; char *name;
int lineno; int lineno;
int flags; int flags;
...@@ -36,7 +32,7 @@ typedef enum tristate { ...@@ -36,7 +32,7 @@ typedef enum tristate {
} tristate; } tristate;
enum expr_type { enum expr_type {
E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_CHOICE, E_SYMBOL E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_CHOICE, E_SYMBOL, E_RANGE
}; };
union expr_data { union expr_data {
...@@ -45,18 +41,10 @@ union expr_data { ...@@ -45,18 +41,10 @@ union expr_data {
}; };
struct expr { struct expr {
#ifdef CML1
int token;
#else
enum expr_type type; enum expr_type type;
#endif
union expr_data left, right; union expr_data left, right;
}; };
#define E_TRI(ev) ((ev).tri)
#define E_EXPR(ev) ((ev).expr)
#define E_CALC(ev) (E_TRI(ev) = expr_calc_value(E_EXPR(ev)))
#define E_OR(dep1, dep2) (((dep1)>(dep2))?(dep1):(dep2)) #define E_OR(dep1, dep2) (((dep1)>(dep2))?(dep1):(dep2))
#define E_AND(dep1, dep2) (((dep1)<(dep2))?(dep1):(dep2)) #define E_AND(dep1, dep2) (((dep1)<(dep2))?(dep1):(dep2))
#define E_NOT(dep) (2-(dep)) #define E_NOT(dep) (2-(dep))
...@@ -66,12 +54,8 @@ struct expr_value { ...@@ -66,12 +54,8 @@ struct expr_value {
tristate tri; tristate tri;
}; };
#define S_VAL(sv) ((sv).value)
#define S_TRI(sv) ((sv).tri)
#define S_EQ(sv1, sv2) (S_VAL(sv1) == S_VAL(sv2) || !strcmp(S_VAL(sv1), S_VAL(sv2)))
struct symbol_value { struct symbol_value {
void *value; void *val;
tristate tri; tristate tri;
}; };
...@@ -83,31 +67,17 @@ struct symbol { ...@@ -83,31 +67,17 @@ struct symbol {
struct symbol *next; struct symbol *next;
char *name; char *name;
char *help; char *help;
#ifdef CML1
int type;
#else
enum symbol_type type; enum symbol_type type;
#endif struct symbol_value curr, user;
struct symbol_value curr, def;
tristate visible; tristate visible;
int flags; int flags;
struct property *prop; struct property *prop;
struct expr *dep, *dep2; struct expr *dep, *dep2;
struct menu *menu; struct expr_value rev_dep;
}; };
#define for_all_symbols(i, sym) for (i = 0; i < 257; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER) #define for_all_symbols(i, sym) for (i = 0; i < 257; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER)
#ifdef CML1
#define SYMBOL_UNKNOWN S_UNKNOWN
#define SYMBOL_BOOLEAN S_BOOLEAN
#define SYMBOL_TRISTATE S_TRISTATE
#define SYMBOL_INT S_INT
#define SYMBOL_HEX S_HEX
#define SYMBOL_STRING S_STRING
#define SYMBOL_OTHER S_OTHER
#endif
#define SYMBOL_YES 0x0001 #define SYMBOL_YES 0x0001
#define SYMBOL_MOD 0x0002 #define SYMBOL_MOD 0x0002
#define SYMBOL_NO 0x0004 #define SYMBOL_NO 0x0004
...@@ -122,34 +92,28 @@ struct symbol { ...@@ -122,34 +92,28 @@ struct symbol {
#define SYMBOL_CHANGED 0x0400 #define SYMBOL_CHANGED 0x0400
#define SYMBOL_NEW 0x0800 #define SYMBOL_NEW 0x0800
#define SYMBOL_AUTO 0x1000 #define SYMBOL_AUTO 0x1000
#define SYMBOL_CHECKED 0x2000
#define SYMBOL_CHECK_DONE 0x4000
#define SYMBOL_WARNED 0x8000
#define SYMBOL_MAXLENGTH 256 #define SYMBOL_MAXLENGTH 256
#define SYMBOL_HASHSIZE 257 #define SYMBOL_HASHSIZE 257
#define SYMBOL_HASHMASK 0xff #define SYMBOL_HASHMASK 0xff
enum prop_type { enum prop_type {
P_UNKNOWN, P_PROMPT, P_COMMENT, P_MENU, P_ROOTMENU, P_DEFAULT, P_CHOICE P_UNKNOWN, P_PROMPT, P_COMMENT, P_MENU, P_DEFAULT, P_CHOICE, P_SELECT, P_RANGE
}; };
struct property { struct property {
struct property *next; struct property *next;
struct symbol *sym; struct symbol *sym;
#ifdef CML1
int token;
#else
enum prop_type type; enum prop_type type;
#endif
const char *text; const char *text;
struct symbol *def;
struct expr_value visible; struct expr_value visible;
struct expr *dep; struct expr *expr;
struct expr *dep2;
struct menu *menu; struct menu *menu;
struct file *file; struct file *file;
int lineno; int lineno;
#ifdef CML1
struct property *next_pos;
#endif
}; };
#define for_all_properties(sym, st, tok) \ #define for_all_properties(sym, st, tok) \
...@@ -176,6 +140,7 @@ struct menu { ...@@ -176,6 +140,7 @@ struct menu {
}; };
#define MENU_CHANGED 0x0001 #define MENU_CHANGED 0x0001
#define MENU_ROOT 0x0002
#ifndef SWIG #ifndef SWIG
...@@ -186,18 +151,12 @@ struct file *lookup_file(const char *name); ...@@ -186,18 +151,12 @@ struct file *lookup_file(const char *name);
extern struct symbol symbol_yes, symbol_no, symbol_mod; extern struct symbol symbol_yes, symbol_no, symbol_mod;
extern struct symbol *modules_sym; extern struct symbol *modules_sym;
extern int cdebug; extern int cdebug;
extern int print_type;
struct expr *expr_alloc_symbol(struct symbol *sym); struct expr *expr_alloc_symbol(struct symbol *sym);
#ifdef CML1
struct expr *expr_alloc_one(int token, struct expr *ce);
struct expr *expr_alloc_two(int token, struct expr *e1, struct expr *e2);
struct expr *expr_alloc_comp(int token, struct symbol *s1, struct symbol *s2);
#else
struct expr *expr_alloc_one(enum expr_type type, struct expr *ce); struct expr *expr_alloc_one(enum expr_type type, struct expr *ce);
struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2); struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2);
struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2); struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2);
#endif
struct expr *expr_alloc_and(struct expr *e1, struct expr *e2); struct expr *expr_alloc_and(struct expr *e1, struct expr *e2);
struct expr *expr_alloc_or(struct expr *e1, struct expr *e2);
struct expr *expr_copy(struct expr *org); struct expr *expr_copy(struct expr *org);
void expr_free(struct expr *e); void expr_free(struct expr *e);
int expr_eq(struct expr *e1, struct expr *e2); int expr_eq(struct expr *e1, struct expr *e2);
...@@ -217,17 +176,6 @@ struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symb ...@@ -217,17 +176,6 @@ struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symb
void expr_fprint(struct expr *e, FILE *out); void expr_fprint(struct expr *e, FILE *out);
void print_expr(int mask, struct expr *e, int prevtoken); void print_expr(int mask, struct expr *e, int prevtoken);
#ifdef CML1
static inline int expr_is_yes(struct expr *e)
{
return !e || (e->token == WORD && e->left.sym == &symbol_yes);
}
static inline int expr_is_no(struct expr *e)
{
return e && (e->token == WORD && e->left.sym == &symbol_no);
}
#else
static inline int expr_is_yes(struct expr *e) static inline int expr_is_yes(struct expr *e)
{ {
return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes); return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes);
...@@ -238,7 +186,6 @@ static inline int expr_is_no(struct expr *e) ...@@ -238,7 +186,6 @@ static inline int expr_is_no(struct expr *e)
return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no); return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no);
} }
#endif #endif
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }
......
...@@ -164,8 +164,6 @@ const char *dbg_print_ptype(int val) ...@@ -164,8 +164,6 @@ const char *dbg_print_ptype(int val)
strcpy(buf, "comment"); strcpy(buf, "comment");
if (val == P_MENU) if (val == P_MENU)
strcpy(buf, "menu"); strcpy(buf, "menu");
if (val == P_ROOTMENU)
strcpy(buf, "rootmenu");
if (val == P_DEFAULT) if (val == P_DEFAULT)
strcpy(buf, "default"); strcpy(buf, "default");
if (val == P_CHOICE) if (val == P_CHOICE)
...@@ -798,7 +796,7 @@ void on_back_pressed(GtkButton * button, gpointer user_data) ...@@ -798,7 +796,7 @@ void on_back_pressed(GtkButton * button, gpointer user_data)
current = current->parent; current = current->parent;
ptype = current->prompt ? current->prompt->type : P_UNKNOWN; ptype = current->prompt ? current->prompt->type : P_UNKNOWN;
if ((ptype != P_ROOTMENU) && (ptype != P_MENU)) if (ptype != P_MENU)
current = current->parent; current = current->parent;
display_tree_part(); display_tree_part();
...@@ -836,6 +834,8 @@ void on_split_clicked(GtkButton * button, gpointer user_data) ...@@ -836,6 +834,8 @@ void on_split_clicked(GtkButton * button, gpointer user_data)
gtk_widget_show(tree1_w); gtk_widget_show(tree1_w);
gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h); gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
gtk_paned_set_position(GTK_PANED(hpaned), w / 2); gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
if (tree2)
gtk_tree_store_clear(tree2);
display_list(); display_list();
} }
...@@ -922,8 +922,10 @@ static void change_sym_value(struct menu *menu, gint col) ...@@ -922,8 +922,10 @@ static void change_sym_value(struct menu *menu, gint col)
config_changed = TRUE; config_changed = TRUE;
if (view_mode == FULL_VIEW) if (view_mode == FULL_VIEW)
update_tree(&rootmenu, NULL); update_tree(&rootmenu, NULL);
else if (view_mode == SPLIT_VIEW) else if (view_mode == SPLIT_VIEW) {
update_tree(current, NULL); update_tree(current, NULL);
display_list();
}
else if (view_mode == SINGLE_VIEW) else if (view_mode == SINGLE_VIEW)
display_tree_part(); //fixme: keep exp/coll display_tree_part(); //fixme: keep exp/coll
break; break;
...@@ -949,8 +951,10 @@ static void toggle_sym_value(struct menu *menu) ...@@ -949,8 +951,10 @@ static void toggle_sym_value(struct menu *menu)
sym_set_tristate_value(menu->sym, newval); sym_set_tristate_value(menu->sym, newval);
if (view_mode == FULL_VIEW) if (view_mode == FULL_VIEW)
update_tree(&rootmenu, NULL); update_tree(&rootmenu, NULL);
else if (view_mode == SPLIT_VIEW) else if (view_mode == SPLIT_VIEW) {
update_tree(current, NULL); update_tree(current, NULL);
display_list();
}
else if (view_mode == SINGLE_VIEW) else if (view_mode == SINGLE_VIEW)
display_tree_part(); //fixme: keep exp/coll display_tree_part(); //fixme: keep exp/coll
} }
...@@ -1035,8 +1039,7 @@ on_treeview2_button_press_event(GtkWidget * widget, ...@@ -1035,8 +1039,7 @@ on_treeview2_button_press_event(GtkWidget * widget,
enum prop_type ptype; enum prop_type ptype;
ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
if (((ptype == P_MENU) || (ptype == P_ROOTMENU)) && if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) {
(view_mode == SINGLE_VIEW) && (col == COL_OPTION)) {
// goes down into menu // goes down into menu
current = menu; current = menu;
display_tree_part(); display_tree_part();
...@@ -1192,7 +1195,6 @@ static gchar **fill_row(struct menu *menu) ...@@ -1192,7 +1195,6 @@ static gchar **fill_row(struct menu *menu)
ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
switch (ptype) { switch (ptype) {
case P_MENU: case P_MENU:
case P_ROOTMENU:
row[COL_PIXBUF] = (gchar *) xpm_menu; row[COL_PIXBUF] = (gchar *) xpm_menu;
if (view_mode != FULL_VIEW) if (view_mode != FULL_VIEW)
row[COL_PIXVIS] = GINT_TO_POINTER(TRUE); row[COL_PIXVIS] = GINT_TO_POINTER(TRUE);
...@@ -1477,11 +1479,11 @@ static void display_tree(struct menu *menu) ...@@ -1477,11 +1479,11 @@ static void display_tree(struct menu *menu)
if (sym) if (sym)
sym->flags &= ~SYMBOL_CHANGED; sym->flags &= ~SYMBOL_CHANGED;
if ((view_mode == SPLIT_VIEW) && (ptype != P_ROOTMENU) && if ((view_mode == SPLIT_VIEW) && !(child->flags & MENU_ROOT) &&
(tree == tree1)) (tree == tree1))
continue; continue;
if ((view_mode == SPLIT_VIEW) && (ptype == P_ROOTMENU) && if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT) &&
(tree == tree2)) (tree == tree2))
continue; continue;
...@@ -1503,7 +1505,7 @@ static void display_tree(struct menu *menu) ...@@ -1503,7 +1505,7 @@ static void display_tree(struct menu *menu)
&& (tree == tree2)) && (tree == tree2))
continue; continue;
if (((menu != &rootmenu) && (ptype != P_ROOTMENU)) || if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT)) ||
(view_mode == FULL_VIEW) (view_mode == FULL_VIEW)
|| (view_mode == SPLIT_VIEW)) { || (view_mode == SPLIT_VIEW)) {
indent++; indent++;
...@@ -1525,8 +1527,6 @@ static void display_tree_part(void) ...@@ -1525,8 +1527,6 @@ static void display_tree_part(void)
/* Display the list in the left frame (split view) */ /* Display the list in the left frame (split view) */
static void display_list(void) static void display_list(void)
{ {
if (tree2)
gtk_tree_store_clear(tree2);
if (tree1) if (tree1)
gtk_tree_store_clear(tree1); gtk_tree_store_clear(tree1);
...@@ -1542,7 +1542,7 @@ static void fixup_rootmenu(struct menu *menu) ...@@ -1542,7 +1542,7 @@ static void fixup_rootmenu(struct menu *menu)
if (!menu->prompt || menu->prompt->type != P_MENU) if (!menu->prompt || menu->prompt->type != P_MENU)
return; return;
menu->prompt->type = P_ROOTMENU; menu->flags |= MENU_ROOT;
for (child = menu->list; child; child = child->next) for (child = menu->list; child; child = child->next)
fixup_rootmenu(child); fixup_rootmenu(child);
} }
......
This diff is collapsed.
...@@ -49,9 +49,11 @@ void menu_add_menu(void); ...@@ -49,9 +49,11 @@ void menu_add_menu(void);
void menu_end_menu(void); void menu_end_menu(void);
void menu_add_entry(struct symbol *sym); void menu_add_entry(struct symbol *sym);
void menu_end_entry(void); void menu_end_entry(void);
struct property *create_prop(enum prop_type type);
void menu_add_dep(struct expr *dep); void menu_add_dep(struct expr *dep);
struct property *menu_add_prop(int token, char *prompt, struct symbol *def, struct expr *dep); struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep);
void menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
void menu_finalize(struct menu *parent); void menu_finalize(struct menu *parent);
void menu_set_type(int type); void menu_set_type(int type);
struct file *file_lookup(const char *name); struct file *file_lookup(const char *name);
...@@ -64,16 +66,19 @@ extern struct menu *current_menu; ...@@ -64,16 +66,19 @@ extern struct menu *current_menu;
void sym_init(void); void sym_init(void);
void sym_clear_all_valid(void); void sym_clear_all_valid(void);
void sym_set_changed(struct symbol *sym); void sym_set_changed(struct symbol *sym);
struct symbol *sym_check_deps(struct symbol *sym);
struct property *prop_alloc(enum prop_type type, struct symbol *sym);
struct symbol *prop_get_symbol(struct property *prop);
static inline tristate sym_get_tristate_value(struct symbol *sym) static inline tristate sym_get_tristate_value(struct symbol *sym)
{ {
return S_TRI(sym->curr); return sym->curr.tri;
} }
static inline struct symbol *sym_get_choice_value(struct symbol *sym) static inline struct symbol *sym_get_choice_value(struct symbol *sym)
{ {
return (struct symbol *)S_VAL(sym->curr); return (struct symbol *)sym->curr.val;
} }
static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval) static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval)
...@@ -98,7 +103,6 @@ static inline bool sym_is_optional(struct symbol *sym) ...@@ -98,7 +103,6 @@ static inline bool sym_is_optional(struct symbol *sym)
static inline bool sym_has_value(struct symbol *sym) static inline bool sym_has_value(struct symbol *sym)
{ {
//return S_VAL(sym->def) != NULL;
return sym->flags & SYMBOL_NEW ? false : true; return sym->flags & SYMBOL_NEW ? false : true;
} }
......
...@@ -18,13 +18,14 @@ P(sym_change_count,int,); ...@@ -18,13 +18,14 @@ P(sym_change_count,int,);
P(sym_lookup,struct symbol *,(const char *name, int isconst)); P(sym_lookup,struct symbol *,(const char *name, int isconst));
P(sym_find,struct symbol *,(const char *name)); P(sym_find,struct symbol *,(const char *name));
P(sym_type_name,const char *,(int type)); P(sym_type_name,const char *,(enum symbol_type type));
P(sym_calc_value,void,(struct symbol *sym)); P(sym_calc_value,void,(struct symbol *sym));
P(sym_get_type,int,(struct symbol *sym)); P(sym_get_type,enum symbol_type,(struct symbol *sym));
P(sym_tristate_within_range,bool,(struct symbol *sym,tristate tri)); P(sym_tristate_within_range,bool,(struct symbol *sym,tristate tri));
P(sym_set_tristate_value,bool,(struct symbol *sym,tristate tri)); P(sym_set_tristate_value,bool,(struct symbol *sym,tristate tri));
P(sym_toggle_tristate_value,tristate,(struct symbol *sym)); P(sym_toggle_tristate_value,tristate,(struct symbol *sym));
P(sym_string_valid,bool,(struct symbol *sym, const char *newval)); P(sym_string_valid,bool,(struct symbol *sym, const char *newval));
P(sym_string_within_range,bool,(struct symbol *sym, const char *str));
P(sym_set_string_value,bool,(struct symbol *sym, const char *newval)); P(sym_set_string_value,bool,(struct symbol *sym, const char *newval));
P(sym_is_changable,bool,(struct symbol *sym)); P(sym_is_changable,bool,(struct symbol *sym));
P(sym_get_choice_prop,struct property *,(struct symbol *sym)); P(sym_get_choice_prop,struct property *,(struct symbol *sym));
......
...@@ -384,7 +384,10 @@ static void build_conf(struct menu *menu) ...@@ -384,7 +384,10 @@ static void build_conf(struct menu *menu)
switch (type) { switch (type) {
case S_BOOLEAN: case S_BOOLEAN:
cprint("t%p", menu); cprint("t%p", menu);
cprint1("[%c]", val == no ? ' ' : '*'); if (sym_is_changable(sym))
cprint1("[%c]", val == no ? ' ' : '*');
else
cprint1("---");
break; break;
case S_TRISTATE: case S_TRISTATE:
cprint("t%p", menu); cprint("t%p", menu);
...@@ -393,7 +396,10 @@ static void build_conf(struct menu *menu) ...@@ -393,7 +396,10 @@ static void build_conf(struct menu *menu)
case mod: ch = 'M'; break; case mod: ch = 'M'; break;
default: ch = ' '; break; default: ch = ' '; break;
} }
cprint1("<%c>", ch); if (sym_is_changable(sym))
cprint1("<%c>", ch);
else
cprint1("---");
break; break;
default: default:
cprint("s%p", menu); cprint("s%p", menu);
...@@ -402,13 +408,15 @@ static void build_conf(struct menu *menu) ...@@ -402,13 +408,15 @@ static void build_conf(struct menu *menu)
if (tmp < 0) if (tmp < 0)
tmp = 0; tmp = 0;
cprint1("%*c%s%s", tmp, ' ', menu_get_prompt(menu), cprint1("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
sym_has_value(sym) ? "" : " (NEW)"); (sym_has_value(sym) || !sym_is_changable(sym)) ?
"" : " (NEW)");
cprint_done(); cprint_done();
goto conf_childs; goto conf_childs;
} }
} }
cprint1("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu), cprint1("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
sym_has_value(sym) ? "" : " (NEW)"); (sym_has_value(sym) || !sym_is_changable(sym)) ?
"" : " (NEW)");
if (menu->prompt->type == P_MENU) { if (menu->prompt->type == P_MENU) {
cprint1(" --->"); cprint1(" --->");
cprint_done(); cprint_done();
...@@ -780,10 +788,12 @@ int main(int ac, char **av) ...@@ -780,10 +788,12 @@ int main(int ac, char **av)
conf_write(NULL); conf_write(NULL);
printf("\n\n" printf("\n\n"
"*** End of Linux kernel configuration.\n" "*** End of Linux kernel configuration.\n"
"*** Check the top-level Makefile for additional configuration.\n" "*** Execute 'make' to build the kernel or try 'make help'."
"*** Next, you may run 'make bzImage', 'make bzdisk', or 'make install'.\n\n"); "\n\n");
} else } else
printf("\n\nYour kernel configuration changes were NOT saved.\n\n"); printf("\n\n"
"Your kernel configuration changes were NOT saved."
"\n\n");
return 0; return 0;
} }
...@@ -94,56 +94,43 @@ void menu_set_type(int type) ...@@ -94,56 +94,43 @@ void menu_set_type(int type)
sym->type = type; sym->type = type;
return; return;
} }
fprintf(stderr, "%s:%d: type of '%s' redefined from '%s' to '%s'\n", fprintf(stderr, "%s:%d:warning: type of '%s' redefined from '%s' to '%s'\n",
current_entry->file->name, current_entry->lineno, current_entry->file->name, current_entry->lineno,
sym->name ? sym->name : "<choice>", sym_type_name(sym->type), sym_type_name(type)); sym->name ? sym->name : "<choice>", sym_type_name(sym->type), sym_type_name(type));
} }
struct property *create_prop(enum prop_type type) struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
{ {
struct property *prop; struct property *prop = prop_alloc(type, current_entry->sym);
prop = malloc(sizeof(*prop));
memset(prop, 0, sizeof(*prop));
prop->type = type;
prop->file = current_file;
prop->lineno = zconf_lineno();
return prop;
}
struct property *menu_add_prop(int token, char *prompt, struct symbol *def, struct expr *dep)
{
struct property *prop = create_prop(token);
struct property **propp;
prop->sym = current_entry->sym;
prop->menu = current_entry; prop->menu = current_entry;
prop->text = prompt; prop->text = prompt;
prop->def = def; prop->expr = expr;
E_EXPR(prop->visible) = menu_check_dep(dep); prop->visible.expr = menu_check_dep(dep);
if (prompt) if (prompt) {
if (current_entry->prompt)
fprintf(stderr, "%s:%d: prompt redefined\n",
current_entry->file->name, current_entry->lineno);
current_entry->prompt = prop; current_entry->prompt = prop;
/* append property to the prop list of symbol */
if (prop->sym) {
for (propp = &prop->sym->prop; *propp; propp = &(*propp)->next)
;
*propp = prop;
} }
return prop; return prop;
} }
void menu_add_prompt(int token, char *prompt, struct expr *dep) void menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
{ {
current_entry->prompt = menu_add_prop(token, prompt, NULL, dep); menu_add_prop(type, prompt, NULL, dep);
} }
void menu_add_default(int token, struct symbol *def, struct expr *dep) void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
{ {
current_entry->prompt = menu_add_prop(token, NULL, def, dep); menu_add_prop(type, NULL, expr, dep);
}
void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
{
menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
} }
void menu_finalize(struct menu *parent) void menu_finalize(struct menu *parent)
...@@ -151,7 +138,7 @@ void menu_finalize(struct menu *parent) ...@@ -151,7 +138,7 @@ void menu_finalize(struct menu *parent)
struct menu *menu, *last_menu; struct menu *menu, *last_menu;
struct symbol *sym; struct symbol *sym;
struct property *prop; struct property *prop;
struct expr *parentdep, *basedep, *dep, *dep2; struct expr *parentdep, *basedep, *dep, *dep2, **ep;
sym = parent->sym; sym = parent->sym;
if (parent->list) { if (parent->list) {
...@@ -168,7 +155,7 @@ void menu_finalize(struct menu *parent) ...@@ -168,7 +155,7 @@ void menu_finalize(struct menu *parent)
} }
parentdep = expr_alloc_symbol(sym); parentdep = expr_alloc_symbol(sym);
} else if (parent->prompt) } else if (parent->prompt)
parentdep = E_EXPR(parent->prompt->visible); parentdep = parent->prompt->visible.expr;
else else
parentdep = parent->dep; parentdep = parent->dep;
...@@ -184,23 +171,28 @@ void menu_finalize(struct menu *parent) ...@@ -184,23 +171,28 @@ void menu_finalize(struct menu *parent)
for (; prop; prop = prop->next) { for (; prop; prop = prop->next) {
if (prop->menu != menu) if (prop->menu != menu)
continue; continue;
dep = expr_transform(E_EXPR(prop->visible)); dep = expr_transform(prop->visible.expr);
dep = expr_alloc_and(expr_copy(basedep), dep); dep = expr_alloc_and(expr_copy(basedep), dep);
dep = expr_eliminate_dups(dep); dep = expr_eliminate_dups(dep);
if (menu->sym && menu->sym->type != S_TRISTATE) if (menu->sym && menu->sym->type != S_TRISTATE)
dep = expr_trans_bool(dep); dep = expr_trans_bool(dep);
E_EXPR(prop->visible) = dep; prop->visible.expr = dep;
if (prop->type == P_SELECT) {
struct symbol *es = prop_get_symbol(prop);
es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
}
} }
} }
for (menu = parent->list; menu; menu = menu->next) for (menu = parent->list; menu; menu = menu->next)
menu_finalize(menu); menu_finalize(menu);
} else if (sym) { } else if (sym) {
basedep = parent->prompt ? E_EXPR(parent->prompt->visible) : NULL; basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no); basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
basedep = expr_eliminate_dups(expr_transform(basedep)); basedep = expr_eliminate_dups(expr_transform(basedep));
last_menu = NULL; last_menu = NULL;
for (menu = parent->next; menu; menu = menu->next) { for (menu = parent->next; menu; menu = menu->next) {
dep = menu->prompt ? E_EXPR(menu->prompt->visible) : menu->dep; dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
if (!expr_contains_symbol(dep, sym)) if (!expr_contains_symbol(dep, sym))
break; break;
if (expr_depends_symbol(dep, sym)) if (expr_depends_symbol(dep, sym))
...@@ -229,14 +221,20 @@ void menu_finalize(struct menu *parent) ...@@ -229,14 +221,20 @@ void menu_finalize(struct menu *parent)
for (menu = parent->list; menu; menu = menu->next) { for (menu = parent->list; menu; menu = menu->next) {
if (sym && sym_is_choice(sym) && menu->sym) { if (sym && sym_is_choice(sym) && menu->sym) {
menu->sym->flags |= SYMBOL_CHOICEVAL; menu->sym->flags |= SYMBOL_CHOICEVAL;
for (prop = menu->sym->prop; prop; prop = prop->next) {
if (prop->type != P_DEFAULT)
continue;
fprintf(stderr, "%s:%d:warning: defaults for choice values not supported\n",
prop->file->name, prop->lineno);
}
current_entry = menu; current_entry = menu;
menu_set_type(sym->type); menu_set_type(sym->type);
menu_add_prop(P_CHOICE, NULL, parent->sym, NULL); menu_add_symbol(P_CHOICE, sym, NULL);
prop = sym_get_choice_prop(parent->sym); prop = sym_get_choice_prop(sym);
//dep = expr_alloc_one(E_CHOICE, dep); for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
//dep->right.sym = menu->sym; ;
prop->dep = expr_alloc_one(E_CHOICE, prop->dep); *ep = expr_alloc_one(E_CHOICE, NULL);
prop->dep->right.sym = menu->sym; (*ep)->right.sym = menu->sym;
} }
if (menu->list && (!menu->prompt || !menu->prompt->text)) { if (menu->list && (!menu->prompt || !menu->prompt->text)) {
for (last_menu = menu->list; ; last_menu = last_menu->next) { for (last_menu = menu->list; ; last_menu = last_menu->next) {
...@@ -249,20 +247,87 @@ void menu_finalize(struct menu *parent) ...@@ -249,20 +247,87 @@ void menu_finalize(struct menu *parent)
menu->list = NULL; menu->list = NULL;
} }
} }
if (sym && !(sym->flags & SYMBOL_WARNED)) {
struct symbol *sym2;
if (sym->type == S_UNKNOWN)
fprintf(stderr, "%s:%d:warning: config symbol defined without type\n",
parent->file->name, parent->lineno);
if (sym_is_choice(sym) && !parent->prompt)
fprintf(stderr, "%s:%d:warning: choice must have a prompt\n",
parent->file->name, parent->lineno);
for (prop = sym->prop; prop; prop = prop->next) {
switch (prop->type) {
case P_DEFAULT:
if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
prop->expr->type != E_SYMBOL)
fprintf(stderr, "%s:%d:warning: default must be a single symbol\n",
prop->file->name, prop->lineno);
break;
case P_SELECT:
sym2 = prop_get_symbol(prop);
if ((sym->type != S_BOOLEAN && sym->type != S_TRISTATE) ||
(sym2->type != S_BOOLEAN && sym2->type != S_TRISTATE))
fprintf(stderr, "%s:%d:warning: enable is only allowed with boolean and tristate symbols\n",
prop->file->name, prop->lineno);
break;
case P_RANGE:
if (sym->type != S_INT && sym->type != S_HEX)
fprintf(stderr, "%s:%d:warning: range is only allowed for int or hex symbols\n",
prop->file->name, prop->lineno);
if (!sym_string_valid(sym, prop->expr->left.sym->name) ||
!sym_string_valid(sym, prop->expr->right.sym->name))
fprintf(stderr, "%s:%d:warning: range is invalid\n",
prop->file->name, prop->lineno);
break;
default:
;
}
}
sym->flags |= SYMBOL_WARNED;
}
if (sym && !sym_is_optional(sym) && parent->prompt) {
sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
expr_alloc_and(parent->prompt->visible.expr,
expr_alloc_symbol(&symbol_mod)));
}
} }
bool menu_is_visible(struct menu *menu) bool menu_is_visible(struct menu *menu)
{ {
struct menu *child;
struct symbol *sym;
tristate visible; tristate visible;
if (!menu->prompt) if (!menu->prompt)
return false; return false;
if (menu->sym) { sym = menu->sym;
sym_calc_value(menu->sym); if (sym) {
visible = E_TRI(menu->prompt->visible); sym_calc_value(sym);
visible = menu->prompt->visible.tri;
} else } else
visible = E_CALC(menu->prompt->visible); visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
return visible != no;
if (sym && sym_is_choice(sym)) {
for (child = menu->list; child; child = child->next)
if (menu_is_visible(child))
break;
if (!child)
return false;
}
if (visible != no)
return true;
if (!sym || sym_get_tristate_value(menu->sym) == no)
return false;
for (child = menu->list; child; child = child->next)
if (menu_is_visible(child))
return true;
return false;
} }
const char *menu_get_prompt(struct menu *menu) const char *menu_get_prompt(struct menu *menu)
...@@ -285,7 +350,7 @@ struct menu *menu_get_parent_menu(struct menu *menu) ...@@ -285,7 +350,7 @@ struct menu *menu_get_parent_menu(struct menu *menu)
for (; menu != &rootmenu; menu = menu->parent) { for (; menu != &rootmenu; menu = menu->parent) {
type = menu->prompt ? menu->prompt->type : 0; type = menu->prompt ? menu->prompt->type : 0;
if (type == P_MENU || type == P_ROOTMENU) if (type == P_MENU)
break; break;
} }
return menu; return menu;
......
...@@ -65,11 +65,11 @@ void ConfigList::updateMenuList(P* parent, struct menu* menu) ...@@ -65,11 +65,11 @@ void ConfigList::updateMenuList(P* parent, struct menu* menu)
switch (mode) { switch (mode) {
case menuMode: case menuMode:
if (type != P_ROOTMENU) if (!(child->flags & MENU_ROOT))
goto hide; goto hide;
break; break;
case symbolMode: case symbolMode:
if (type == P_ROOTMENU) if (child->flags & MENU_ROOT)
goto hide; goto hide;
break; break;
default: default:
...@@ -83,8 +83,7 @@ void ConfigList::updateMenuList(P* parent, struct menu* menu) ...@@ -83,8 +83,7 @@ void ConfigList::updateMenuList(P* parent, struct menu* menu)
else else
item->testUpdateMenu(visible); item->testUpdateMenu(visible);
if (mode == fullMode || mode == menuMode || if (mode == fullMode || mode == menuMode || type != P_MENU)
(type != P_MENU && type != P_ROOTMENU))
updateMenuList(item, child); updateMenuList(item, child);
else else
updateMenuList(item, 0); updateMenuList(item, 0);
...@@ -140,7 +139,6 @@ void ConfigItem::updateMenu(void) ...@@ -140,7 +139,6 @@ void ConfigItem::updateMenu(void)
if (prop) switch (prop->type) { if (prop) switch (prop->type) {
case P_MENU: case P_MENU:
case P_ROOTMENU:
if (list->mode == singleMode || list->mode == symbolMode) { if (list->mode == singleMode || list->mode == symbolMode) {
/* a menuconfig entry is displayed differently /* a menuconfig entry is displayed differently
* depending whether it's at the view root or a child. * depending whether it's at the view root or a child.
...@@ -172,6 +170,7 @@ void ConfigItem::updateMenu(void) ...@@ -172,6 +170,7 @@ void ConfigItem::updateMenu(void)
char ch; char ch;
if (!sym_is_changable(sym) && !list->showAll) { if (!sym_is_changable(sym) && !list->showAll) {
setPixmap(promptColIdx, 0);
setText(noColIdx, 0); setText(noColIdx, 0);
setText(modColIdx, 0); setText(modColIdx, 0);
setText(yesColIdx, 0); setText(yesColIdx, 0);
...@@ -288,7 +287,7 @@ void ConfigItem::init(void) ...@@ -288,7 +287,7 @@ void ConfigItem::init(void)
ConfigItem::~ConfigItem(void) ConfigItem::~ConfigItem(void)
{ {
if (menu) { if (menu) {
ConfigItem** ip = &(ConfigItem*)menu->data; ConfigItem** ip = (ConfigItem**)&menu->data;
for (; *ip; ip = &(*ip)->nextItem) { for (; *ip; ip = &(*ip)->nextItem) {
if (*ip == this) { if (*ip == this) {
*ip = nextItem; *ip = nextItem;
...@@ -333,7 +332,7 @@ ConfigList::ConfigList(ConfigView* p, ConfigMainWindow* cv) ...@@ -333,7 +332,7 @@ ConfigList::ConfigList(ConfigView* p, ConfigMainWindow* cv)
updateAll(false), updateAll(false),
symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no), symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no),
choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no), choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no),
menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void),
showAll(false), showName(false), showRange(false), showData(false), showAll(false), showName(false), showRange(false), showData(false),
rootEntry(0) rootEntry(0)
{ {
...@@ -392,7 +391,7 @@ void ConfigList::updateSelection(void) ...@@ -392,7 +391,7 @@ void ConfigList::updateSelection(void)
if (!menu) if (!menu)
return; return;
type = menu->prompt ? menu->prompt->type : P_UNKNOWN; type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
if (mode == menuMode && (type == P_MENU || type == P_ROOTMENU)) if (mode == menuMode && type == P_MENU)
emit menuSelected(menu); emit menuSelected(menu);
} }
...@@ -403,7 +402,8 @@ void ConfigList::updateList(ConfigItem* item) ...@@ -403,7 +402,8 @@ void ConfigList::updateList(ConfigItem* item)
if (!rootEntry) if (!rootEntry)
goto update; goto update;
if ((mode == singleMode || mode == symbolMode) && rootEntry != &rootmenu) { if (rootEntry != &rootmenu && (mode == singleMode ||
(mode == symbolMode && rootEntry->parent != &rootmenu))) {
item = firstChild(); item = firstChild();
if (!item) if (!item)
item = new ConfigItem(this, 0, true); item = new ConfigItem(this, 0, true);
...@@ -507,7 +507,7 @@ void ConfigList::setRootMenu(struct menu *menu) ...@@ -507,7 +507,7 @@ void ConfigList::setRootMenu(struct menu *menu)
if (rootEntry == menu) if (rootEntry == menu)
return; return;
type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN; type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN;
if (type != P_MENU && type != P_ROOTMENU) if (type != P_MENU)
return; return;
updateMenuList(this, 0); updateMenuList(this, 0);
rootEntry = menu; rootEntry = menu;
...@@ -518,13 +518,12 @@ void ConfigList::setRootMenu(struct menu *menu) ...@@ -518,13 +518,12 @@ void ConfigList::setRootMenu(struct menu *menu)
void ConfigList::setParentMenu(void) void ConfigList::setParentMenu(void)
{ {
ConfigItem* item; ConfigItem* item;
struct menu *oldroot, *newroot; struct menu *oldroot;
oldroot = rootEntry; oldroot = rootEntry;
newroot = menu_get_parent_menu(oldroot); if (rootEntry == &rootmenu)
if (newroot == oldroot)
return; return;
setRootMenu(newroot); setRootMenu(menu_get_parent_menu(rootEntry->parent));
QListViewItemIterator it(this); QListViewItemIterator it(this);
for (; (item = (ConfigItem*)it.current()); it++) { for (; (item = (ConfigItem*)it.current()); it++) {
...@@ -566,7 +565,8 @@ void ConfigList::keyPressEvent(QKeyEvent* ev) ...@@ -566,7 +565,8 @@ void ConfigList::keyPressEvent(QKeyEvent* ev)
if (!menu) if (!menu)
break; break;
type = menu->prompt ? menu->prompt->type : P_UNKNOWN; type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
if ((type == P_MENU || type == P_ROOTMENU) && mode != fullMode) { if (type == P_MENU && rootEntry != menu &&
mode != fullMode && mode != menuMode) {
emit menuSelected(menu); emit menuSelected(menu);
break; break;
} }
...@@ -601,6 +601,7 @@ void ConfigList::contentsMouseReleaseEvent(QMouseEvent* e) ...@@ -601,6 +601,7 @@ void ConfigList::contentsMouseReleaseEvent(QMouseEvent* e)
QPoint p(contentsToViewport(e->pos())); QPoint p(contentsToViewport(e->pos()));
ConfigItem* item = (ConfigItem*)itemAt(p); ConfigItem* item = (ConfigItem*)itemAt(p);
struct menu *menu; struct menu *menu;
enum prop_type ptype;
const QPixmap* pm; const QPixmap* pm;
int idx, x; int idx, x;
...@@ -617,14 +618,17 @@ void ConfigList::contentsMouseReleaseEvent(QMouseEvent* e) ...@@ -617,14 +618,17 @@ void ConfigList::contentsMouseReleaseEvent(QMouseEvent* e)
int off = header()->sectionPos(0) + itemMargin() + int off = header()->sectionPos(0) + itemMargin() +
treeStepSize() * (item->depth() + (rootIsDecorated() ? 1 : 0)); treeStepSize() * (item->depth() + (rootIsDecorated() ? 1 : 0));
if (x >= off && x < off + pm->width()) { if (x >= off && x < off + pm->width()) {
if (item->goParent) if (item->goParent) {
emit parentSelected(); emit parentSelected();
else if (!menu)
break; break;
else if (menu->sym) } else if (!menu)
changeValue(item); break;
else ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
if (ptype == P_MENU && rootEntry != menu &&
mode != fullMode && mode != menuMode)
emit menuSelected(menu); emit menuSelected(menu);
else
changeValue(item);
} }
} }
break; break;
...@@ -671,8 +675,7 @@ void ConfigList::contentsMouseDoubleClickEvent(QMouseEvent* e) ...@@ -671,8 +675,7 @@ void ConfigList::contentsMouseDoubleClickEvent(QMouseEvent* e)
if (!menu) if (!menu)
goto skip; goto skip;
ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
if ((ptype == P_ROOTMENU || ptype == P_MENU) && if (ptype == P_MENU && (mode == singleMode || mode == symbolMode))
(mode == singleMode || mode == symbolMode))
emit menuSelected(menu); emit menuSelected(menu);
else if (menu->sym) else if (menu->sym)
changeValue(item); changeValue(item);
...@@ -880,7 +883,6 @@ ConfigMainWindow::ConfigMainWindow(void) ...@@ -880,7 +883,6 @@ ConfigMainWindow::ConfigMainWindow(void)
connect(menuList, SIGNAL(gotFocus(void)), connect(menuList, SIGNAL(gotFocus(void)),
SLOT(listFocusChanged(void))); SLOT(listFocusChanged(void)));
//showFullView();
showSplitView(); showSplitView();
} }
...@@ -959,36 +961,54 @@ void ConfigMainWindow::setHelp(QListViewItem* item) ...@@ -959,36 +961,54 @@ void ConfigMainWindow::setHelp(QListViewItem* item)
if (showDebug) { if (showDebug) {
debug += "type: "; debug += "type: ";
debug += print_filter(sym_type_name(sym->type)); debug += print_filter(sym_type_name(sym->type));
if (sym_is_choice(sym))
debug += " (choice)";
debug += "<br>"; debug += "<br>";
if (sym->rev_dep.expr) {
debug += "reverse dep: ";
expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE);
debug += "<br>";
}
for (struct property *prop = sym->prop; prop; prop = prop->next) { for (struct property *prop = sym->prop; prop; prop = prop->next) {
switch (prop->type) { switch (prop->type) {
case P_PROMPT: case P_PROMPT:
case P_MENU:
debug += "prompt: "; debug += "prompt: ";
debug += print_filter(prop->text); debug += print_filter(prop->text);
debug += "<br>"; debug += "<br>";
if (prop->visible.expr) {
debug += "&nbsp;&nbsp;dep: ";
expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE);
debug += "<br>";
}
break; break;
case P_DEFAULT: case P_DEFAULT:
debug += "default: "; debug += "default: ";
debug += print_filter(prop->def->name); expr_print(prop->expr, expr_print_help, &debug, E_NONE);
debug += "<br>"; debug += "<br>";
if (prop->visible.expr) { break;
debug += "&nbsp;&nbsp;dep: "; case P_CHOICE:
expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE); if (sym_is_choice(sym)) {
debug += "choice: ";
expr_print(prop->expr, expr_print_help, &debug, E_NONE);
debug += "<br>"; debug += "<br>";
} }
break; break;
case P_CHOICE: case P_SELECT:
debug += "select: ";
expr_print(prop->expr, expr_print_help, &debug, E_NONE);
debug += "<br>";
break;
case P_RANGE:
debug += "range: ";
expr_print(prop->expr, expr_print_help, &debug, E_NONE);
debug += "<br>";
break; break;
default: default:
debug += "unknown property: "; debug += "unknown property: ";
debug += prop_get_type_name(prop->type); debug += prop_get_type_name(prop->type);
debug += "<br>"; debug += "<br>";
} }
if (prop->visible.expr) {
debug += "&nbsp;&nbsp;&nbsp;&nbsp;dep: ";
expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE);
debug += "<br>";
}
} }
debug += "<br>"; debug += "<br>";
} }
...@@ -1002,10 +1022,12 @@ void ConfigMainWindow::setHelp(QListViewItem* item) ...@@ -1002,10 +1022,12 @@ void ConfigMainWindow::setHelp(QListViewItem* item)
if (menu->prompt->visible.expr) { if (menu->prompt->visible.expr) {
debug += "&nbsp;&nbsp;dep: "; debug += "&nbsp;&nbsp;dep: ";
expr_print(menu->prompt->visible.expr, expr_print_help, &debug, E_NONE); expr_print(menu->prompt->visible.expr, expr_print_help, &debug, E_NONE);
debug += "<br>"; debug += "<br><br>";
} }
} }
} }
if (showDebug)
debug += QString().sprintf("defined at %s:%d<br><br>", menu->file->name, menu->lineno);
helpText->setText(head + debug + help); helpText->setText(head + debug + help);
} }
...@@ -1133,6 +1155,8 @@ void ConfigMainWindow::setShowName(bool b) ...@@ -1133,6 +1155,8 @@ void ConfigMainWindow::setShowName(bool b)
return; return;
configList->showName = b; configList->showName = b;
configList->reinit(); configList->reinit();
menuList->showName = b;
menuList->reinit();
} }
void ConfigMainWindow::setShowRange(bool b) void ConfigMainWindow::setShowRange(bool b)
...@@ -1141,6 +1165,8 @@ void ConfigMainWindow::setShowRange(bool b) ...@@ -1141,6 +1165,8 @@ void ConfigMainWindow::setShowRange(bool b)
return; return;
configList->showRange = b; configList->showRange = b;
configList->reinit(); configList->reinit();
menuList->showRange = b;
menuList->reinit();
} }
void ConfigMainWindow::setShowData(bool b) void ConfigMainWindow::setShowData(bool b)
...@@ -1149,6 +1175,8 @@ void ConfigMainWindow::setShowData(bool b) ...@@ -1149,6 +1175,8 @@ void ConfigMainWindow::setShowData(bool b)
return; return;
configList->showData = b; configList->showData = b;
configList->reinit(); configList->reinit();
menuList->showData = b;
menuList->reinit();
} }
/* /*
...@@ -1206,12 +1234,25 @@ void ConfigMainWindow::showAbout(void) ...@@ -1206,12 +1234,25 @@ void ConfigMainWindow::showAbout(void)
void fixup_rootmenu(struct menu *menu) void fixup_rootmenu(struct menu *menu)
{ {
struct menu *child; struct menu *child;
static int menu_cnt = 0;
if (!menu->prompt || menu->prompt->type != P_MENU) menu->flags |= MENU_ROOT;
return; for (child = menu->list; child; child = child->next) {
menu->prompt->type = P_ROOTMENU; if (child->prompt && child->prompt->type == P_MENU) {
for (child = menu->list; child; child = child->next) menu_cnt++;
fixup_rootmenu(child); fixup_rootmenu(child);
menu_cnt--;
} else if (!menu_cnt)
fixup_rootmenu(child);
}
}
static const char *progname;
static void usage(void)
{
printf("%s <config>\n", progname);
exit(0);
} }
int main(int ac, char** av) int main(int ac, char** av)
...@@ -1223,23 +1264,23 @@ int main(int ac, char** av) ...@@ -1223,23 +1264,23 @@ int main(int ac, char** av)
kconfig_load(); kconfig_load();
#endif #endif
progname = av[0];
configApp = new QApplication(ac, av); configApp = new QApplication(ac, av);
#if QT_VERSION >= 300 #if QT_VERSION >= 300
configSettings = new QSettings; configSettings = new QSettings;
#endif #endif
if (ac > 1 && av[1][0] == '-') { if (ac > 1 && av[1][0] == '-') {
switch (av[1][1]) { switch (av[1][1]) {
case 'a':
//showAll = 1;
break;
case 'h': case 'h':
case '?': case '?':
printf("%s <config>\n", av[0]); usage();
exit(0);
} }
name = av[2]; name = av[2];
} else } else
name = av[1]; name = av[1];
if (!name)
usage();
conf_parse(name); conf_parse(name);
fixup_rootmenu(&rootmenu); fixup_rootmenu(&rootmenu);
conf_read(NULL); conf_read(NULL);
......
...@@ -108,7 +108,7 @@ public slots: ...@@ -108,7 +108,7 @@ public slots:
QPixmap symbolYesPix, symbolModPix, symbolNoPix; QPixmap symbolYesPix, symbolModPix, symbolNoPix;
QPixmap choiceYesPix, choiceNoPix; QPixmap choiceYesPix, choiceNoPix;
QPixmap menuPix, menuInvPix, menuBackPix; QPixmap menuPix, menuInvPix, menuBackPix, voidPix;
bool showAll, showName, showRange, showData; bool showAll, showName, showRange, showData;
enum listMode mode; enum listMode mode;
......
This diff is collapsed.
...@@ -106,11 +106,17 @@ n [A-Za-z0-9_] ...@@ -106,11 +106,17 @@ n [A-Za-z0-9_]
"default" BEGIN(PARAM); return T_DEFAULT; "default" BEGIN(PARAM); return T_DEFAULT;
"prompt" BEGIN(PARAM); return T_PROMPT; "prompt" BEGIN(PARAM); return T_PROMPT;
"tristate" BEGIN(PARAM); return T_TRISTATE; "tristate" BEGIN(PARAM); return T_TRISTATE;
"def_tristate" BEGIN(PARAM); return T_DEF_TRISTATE;
"bool" BEGIN(PARAM); return T_BOOLEAN; "bool" BEGIN(PARAM); return T_BOOLEAN;
"boolean" BEGIN(PARAM); return T_BOOLEAN; "boolean" BEGIN(PARAM); return T_BOOLEAN;
"def_bool" BEGIN(PARAM); return T_DEF_BOOLEAN;
"def_boolean" BEGIN(PARAM); return T_DEF_BOOLEAN;
"int" BEGIN(PARAM); return T_INT; "int" BEGIN(PARAM); return T_INT;
"hex" BEGIN(PARAM); return T_HEX; "hex" BEGIN(PARAM); return T_HEX;
"string" BEGIN(PARAM); return T_STRING; "string" BEGIN(PARAM); return T_STRING;
"select" BEGIN(PARAM); return T_SELECT;
"enable" BEGIN(PARAM); return T_SELECT;
"range" BEGIN(PARAM); return T_RANGE;
{n}+ { {n}+ {
alloc_string(yytext, yyleng); alloc_string(yytext, yyleng);
zconflval.string = text; zconflval.string = text;
...@@ -208,7 +214,6 @@ n [A-Za-z0-9_] ...@@ -208,7 +214,6 @@ n [A-Za-z0-9_]
} }
append_string(" ", ts); append_string(" ", ts);
} }
} }
[ \t]*\n/[^ \t\n] { [ \t]*\n/[^ \t\n] {
current_file->lineno++; current_file->lineno++;
...@@ -250,11 +255,11 @@ void zconf_starthelp(void) ...@@ -250,11 +255,11 @@ void zconf_starthelp(void)
static void zconf_endhelp(void) static void zconf_endhelp(void)
{ {
zconflval.string = text; zconflval.string = text;
BEGIN(INITIAL); BEGIN(INITIAL);
} }
/* /*
* Try to open specified file with following names: * Try to open specified file with following names:
* ./name * ./name
* $(srctree)/name * $(srctree)/name
...@@ -347,7 +352,7 @@ static struct buffer *zconf_endfile(void) ...@@ -347,7 +352,7 @@ static struct buffer *zconf_endfile(void)
int zconf_lineno(void) int zconf_lineno(void)
{ {
if (current_buf) if (current_buf)
return current_file->lineno; return current_file->lineno - 1;
else else
return 0; return 0;
} }
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment