* David Weinehall March 24th, 1999
* - Fixed the output of 'Driver Installed' in /proc/mca/pos
* - Made the Integrated Video & SCSI show up even if they have id 0000
+ *
+ * AV November 9th, 1999
+ * - switched to regular procfs methods.
*/
#include <linux/types.h>
/*--------------------------------------------------------------------*/
#ifdef CONFIG_PROC_FS
-
static void mca_do_proc_init(void);
-static int mca_default_procfn(char* buf, int slot);
-
-static ssize_t proc_mca_read(struct file*, char*, size_t, loff_t *);
-
-static struct file_operations proc_mca_operations = {
- NULL, /* llseek */
- proc_mca_read, /* read */
- NULL, /* write */
- NULL, /* readdir */
- NULL, /* poll */
- NULL, /* ioctl */
- NULL, /* mmap */
- NULL, /* open */
- NULL, /* flush */
- NULL, /* release */
- NULL, /* fsync */
- NULL, /* fascync */
- NULL, /* check_media_change */
- NULL, /* revalidate */
- NULL /* lock */
-};
-
-static struct inode_operations proc_mca_inode_operations = {
- &proc_mca_operations, /* default file-ops */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
#endif
/*--------------------------------------------------------------------*/
#ifdef CONFIG_PROC_FS
-int get_mca_info(char *buf)
+int get_mca_info(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
{
int i, j, len = 0;
for(i=0; i<MCA_MAX_SLOT_NR; i++)
{
- len += sprintf(buf+len, "Slot %d: ", i+1);
+ len += sprintf(page+len, "Slot %d: ", i+1);
for(j=0; j<8; j++)
- len += sprintf(buf+len, "%02x ", mca_info->slot[i].pos[j]);
- len += sprintf(buf+len, " %s\n", mca_info->slot[i].name);
+ len += sprintf(page+len, "%02x ", mca_info->slot[i].pos[j]);
+ len += sprintf(page+len, " %s\n", mca_info->slot[i].name);
}
/* Format POS registers of integrated video subsystem */
- len += sprintf(buf+len, "Video : ");
+ len += sprintf(page+len, "Video : ");
for(j=0; j<8; j++)
- len += sprintf(buf+len, "%02x ", mca_info->slot[MCA_INTEGVIDEO].pos[j]);
- len += sprintf(buf+len, " %s\n", mca_info->slot[MCA_INTEGVIDEO].name);
+ len += sprintf(page+len, "%02x ", mca_info->slot[MCA_INTEGVIDEO].pos[j]);
+ len += sprintf(page+len, " %s\n", mca_info->slot[MCA_INTEGVIDEO].name);
/* Format POS registers of integrated SCSI subsystem */
- len += sprintf(buf+len, "SCSI : ");
+ len += sprintf(page+len, "SCSI : ");
for(j=0; j<8; j++)
- len += sprintf(buf+len, "%02x ", mca_info->slot[MCA_INTEGSCSI].pos[j]);
- len += sprintf(buf+len, " %s\n", mca_info->slot[MCA_INTEGSCSI].name);
+ len += sprintf(page+len, "%02x ", mca_info->slot[MCA_INTEGSCSI].pos[j]);
+ len += sprintf(page+len, " %s\n", mca_info->slot[MCA_INTEGSCSI].name);
} else {
/* Leave it empty if MCA not detected - this should *never*
* happen!
*/
}
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
return len;
}
-
-/*--------------------------------------------------------------------*/
-
-void __init mca_do_proc_init(void)
-{
- int i;
- struct proc_dir_entry* node = NULL;
-
- if(mca_info == NULL) return; /* Should never happen */
-
- proc_register(proc_mca, &(struct proc_dir_entry) {
- PROC_MCA_REGISTERS, 3, "pos", S_IFREG|S_IRUGO,
- 1, 0, 0, 0, &proc_mca_inode_operations,});
-
- proc_register(proc_mca, &(struct proc_dir_entry) {
- PROC_MCA_MACHINE, 7, "machine", S_IFREG|S_IRUGO,
- 1, 0, 0, 0, &proc_mca_inode_operations,});
-
- /* Initialize /proc/mca entries for existing adapters */
-
- for(i = 0; i < MCA_NUMADAPTERS; i++) {
- mca_info->slot[i].procfn = 0;
- mca_info->slot[i].dev = 0;
-
- if(!mca_isadapter(i)) continue;
-
- node = (struct proc_dir_entry *)kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL);
-
- if(node == NULL) {
- printk("Failed to allocate memory for MCA proc-entries!");
- return;
- }
- memset(node, 0, sizeof(struct proc_dir_entry));
-
- if(i < MCA_MAX_SLOT_NR) {
- node->low_ino = PROC_MCA_SLOT + i;
- node->namelen = sprintf(mca_info->slot[i].procname,
- "slot%d", i+1);
- } else if(i == MCA_INTEGVIDEO) {
- node->low_ino = PROC_MCA_VIDEO;
- node->namelen = sprintf(mca_info->slot[i].procname,
- "video");
- } else if(i == MCA_INTEGSCSI) {
- node->low_ino = PROC_MCA_SCSI;
- node->namelen = sprintf(mca_info->slot[i].procname,
- "scsi");
- }
- node->name = mca_info->slot[i].procname;
- node->mode = S_IFREG | S_IRUGO;
- node->ops = &proc_mca_inode_operations;
- proc_register(proc_mca, node);
- }
-
-} /* mca_do_proc_init() */
-
/*--------------------------------------------------------------------*/
-int mca_default_procfn(char* buf, int slot)
+static int mca_default_procfn(char* buf, struct MCA_adapter *p)
{
int len = 0, i;
-
- /* This really shouldn't happen... */
-
- if(mca_info == NULL) {
- *buf = 0;
- return 0;
- }
+ int slot = p - mca_info->slot;
/* Print out the basic information */
} else if(slot == MCA_INTEGVIDEO) {
len += sprintf(buf+len, "Integrated Video Adapter\n");
}
- if(mca_info->slot[slot].name[0]) {
+ if(p->name[0]) {
/* Drivers might register a name without /proc handler... */
len += sprintf(buf+len, "Adapter Name: %s\n",
- mca_info->slot[slot].name);
+ p->name);
} else {
len += sprintf(buf+len, "Adapter Name: Unknown\n");
}
len += sprintf(buf+len, "Id: %02x%02x\n",
- mca_info->slot[slot].pos[1], mca_info->slot[slot].pos[0]);
+ p->pos[1], p->pos[0]);
len += sprintf(buf+len, "Enabled: %s\nPOS: ",
mca_isenabled(slot) ? "Yes" : "No");
for(i=0; i<8; i++) {
- len += sprintf(buf+len, "%02x ", mca_info->slot[slot].pos[i]);
+ len += sprintf(buf+len, "%02x ", p->pos[i]);
}
len += sprintf(buf+len, "\nDriver Installed: %s",
mca_is_adapter_used(slot) ? "Yes" : "No");
return len;
} /* mca_default_procfn() */
-static int get_mca_machine_info(char* buf)
+static int get_mca_machine_info(char* page, char **start, off_t off,
+ int count, int *eof, void *data)
{
int len = 0;
- len += sprintf(buf+len, "Model Id: 0x%x\n", machine_id);
- len += sprintf(buf+len, "Submodel Id: 0x%x\n", machine_submodel_id);
- len += sprintf(buf+len, "BIOS Revision: 0x%x\n", BIOS_revision);
+ len += sprintf(page+len, "Model Id: 0x%x\n", machine_id);
+ len += sprintf(page+len, "Submodel Id: 0x%x\n", machine_submodel_id);
+ len += sprintf(page+len, "BIOS Revision: 0x%x\n", BIOS_revision);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
return len;
}
-static int mca_fill(char* page, int pid, int type, char** start,
- loff_t *offset, int length)
+static int mca_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
{
+ struct MCA_adapter *p = (struct MCA_adapter *)data;
int len = 0;
- int slot = 0;
-
- switch(type) {
- case PROC_MCA_REGISTERS:
- return get_mca_info(page);
- case PROC_MCA_MACHINE:
- return get_mca_machine_info(page);
- case PROC_MCA_VIDEO:
- slot = MCA_INTEGVIDEO;
- break;
- case PROC_MCA_SCSI:
- slot = MCA_INTEGSCSI;
- break;
- default:
- if(type < PROC_MCA_SLOT || type >= PROC_MCA_LAST) {
- return -EBADF;
- }
- slot = type - PROC_MCA_SLOT;
- break;
- }
-
- /* If we made it here, we better have a valid slot */
/* Get the standard info */
- len = mca_default_procfn(page, slot);
+ len = mca_default_procfn(page, p);
/* Do any device-specific processing, if there is any */
- if(mca_info->slot[slot].procfn) {
- len += mca_info->slot[slot].procfn(page+len, slot,
- mca_info->slot[slot].dev);
+ if(p->procfn) {
+ len += p->procfn(page+len, p-mca_info->slot, p->dev);
}
-
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
return len;
-} /* mca_fill() */
+} /* mca_read_proc() */
-/* Blatantly stolen from fs/proc/array.c, and thus is probably overkill */
-
-#define PROC_BLOCK_SIZE (3*1024)
+/*--------------------------------------------------------------------*/
-static ssize_t proc_mca_read(struct file* file,
- char* buf, size_t count, loff_t *ppos)
+void __init mca_do_proc_init(void)
{
- unsigned long page;
- char *start;
- int length;
- int end;
- unsigned int type, pid;
- struct proc_dir_entry *dp;
- struct inode *inode = file->f_dentry->d_inode;
-
- if(count < 0)
- return -EINVAL;
- if(count > PROC_BLOCK_SIZE)
- count = PROC_BLOCK_SIZE;
- if(!(page = __get_free_page(GFP_KERNEL)))
- return -ENOMEM;
- type = inode->i_ino;
- pid = type >> 16;
- type &= 0x0000ffff;
- start = NULL;
- dp = (struct proc_dir_entry *) inode->u.generic_ip;
- length = mca_fill((char *) page, pid, type,
- &start, ppos, count);
- if(length < 0) {
- free_page(page);
- return length;
- }
- if(start != NULL) {
- /* We have had block-adjusting processing! */
+ int i;
+ struct proc_dir_entry* node = NULL;
+ struct MCA_adapter *p;
- copy_to_user(buf, start, length);
- *ppos += length;
- count = length;
- } else {
- /* Static 4kB (or whatever) block capacity */
+ if(mca_info == NULL) return; /* Should never happen */
+
+ create_proc_read_entry("pos",0,proc_mca,get_mca_info,NULL);
+ create_proc_read_entry("machine",0,proc_mca,get_mca_machine_info,NULL);
+
+ /* Initialize /proc/mca entries for existing adapters */
+
+ for(i = 0; i < MCA_NUMADAPTERS; i++) {
+ p = &mca_info->slot[i];
+ p->procfn = 0;
+
+ if(i < MCA_MAX_SLOT_NR) sprintf(p->procname,"slot%d", i+1);
+ else if(i == MCA_INTEGVIDEO) sprintf(p->procname,"video");
+ else if(i == MCA_INTEGSCSI) sprintf(p->procname,"scsi");
- if(*ppos >= length) {
- free_page(page);
- return 0;
+ if(!mca_isadapter(i)) continue;
+
+ node = create_proc_read_entry(p->procname, 0, proc_mca,
+ mca_read_proc, (void *)p);
+
+ if(node == NULL) {
+ printk("Failed to allocate memory for MCA proc-entries!");
+ return;
}
- if(count + *ppos > length)
- count = length - *ppos;
- end = count + *ppos;
- copy_to_user(buf, (char *) page + *ppos, count);
- *ppos = end;
}
- free_page(page);
- return count;
-} /* proc_mca_read() */
+
+} /* mca_do_proc_init() */
#endif
bool 'Virtual terminal' CONFIG_VT
if [ "$CONFIG_VT" = "y" ]; then
- bool 'Support for console on virtual terminal' CONFIG_VT_CONSOLE
+ bool ' Support for console on virtual terminal' CONFIG_VT_CONSOLE
fi
tristate 'Standard/generic (dumb) serial support' CONFIG_SERIAL
if [ "$CONFIG_SERIAL" = "y" ]; then
fi
bool 'Non-standard serial port support' CONFIG_SERIAL_NONSTANDARD
if [ "$CONFIG_SERIAL_NONSTANDARD" = "y" ]; then
- tristate 'Comtrol Rocketport support' CONFIG_ROCKETPORT
- tristate 'Digiboard Intelligent Async Support' CONFIG_DIGIEPCA
+ tristate ' Comtrol Rocketport support' CONFIG_ROCKETPORT
+ tristate ' Digiboard Intelligent Async Support' CONFIG_DIGIEPCA
if [ "$CONFIG_DIGIEPCA" = "n" ]; then
- tristate 'Digiboard PC/Xx Support' CONFIG_DIGI
+ tristate ' Digiboard PC/Xx Support' CONFIG_DIGI
fi
- tristate 'Cyclades async mux support' CONFIG_CYCLADES
+ tristate ' Cyclades async mux support' CONFIG_CYCLADES
if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_CYCLADES" != "n" ]; then
- bool ' Cyclades-Z interrupt mode operation (EXPERIMENTAL)' CONFIG_CYZ_INTR
+ bool ' Cyclades-Z interrupt mode operation (EXPERIMENTAL)' CONFIG_CYZ_INTR
fi
- bool 'Stallion multiport serial support' CONFIG_STALDRV
+ bool ' Stallion multiport serial support' CONFIG_STALDRV
if [ "$CONFIG_STALDRV" = "y" ]; then
- tristate ' Stallion EasyIO or EC8/32 support' CONFIG_STALLION
- tristate ' Stallion EC8/64, ONboard, Brumby support' CONFIG_ISTALLION
+ tristate ' Stallion EasyIO or EC8/32 support' CONFIG_STALLION
+ tristate ' Stallion EC8/64, ONboard, Brumby support' CONFIG_ISTALLION
fi
- tristate 'SDL RISCom/8 card support' CONFIG_RISCOM8
- tristate 'Computone IntelliPort Plus serial support' CONFIG_COMPUTONE
- tristate 'Specialix IO8+ card support' CONFIG_SPECIALIX
+ tristate ' SDL RISCom/8 card support' CONFIG_RISCOM8
+ tristate ' Computone IntelliPort Plus serial support' CONFIG_COMPUTONE
+ tristate ' Specialix IO8+ card support' CONFIG_SPECIALIX
if [ "$CONFIG_SPECIALIX" != "n" ]; then
- bool 'Specialix DTR/RTS pin is RTS' CONFIG_SPECIALIX_RTSCTS
+ bool ' Specialix DTR/RTS pin is RTS' CONFIG_SPECIALIX_RTSCTS
fi
- tristate 'Specialix SX (and SI) card support' CONFIG_SX
- tristate 'Hayes ESP serial port support' CONFIG_ESPSERIAL
+ tristate ' Specialix SX (and SI) card support' CONFIG_SX
+ tristate ' Hayes ESP serial port support' CONFIG_ESPSERIAL
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- dep_tristate 'Multi-Tech multiport card support' CONFIG_ISI m
+ dep_tristate ' Multi-Tech multiport card support (EXPERIMENTAL)' CONFIG_ISI m
fi
- dep_tristate 'Microgate SyncLink card support' CONFIG_SYNCLINK m
- dep_tristate 'HDLC line discipline support' CONFIG_N_HDLC m
+ dep_tristate ' Microgate SyncLink card support' CONFIG_SYNCLINK m
+ dep_tristate ' HDLC line discipline support' CONFIG_N_HDLC m
fi
bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
- int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
+ int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
fi
if [ "$CONFIG_PARPORT" != "n" ]; then
- dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
- if [ "$CONFIG_PRINTER" != "n" ]; then
- bool ' Support for console on line printer' CONFIG_LP_CONSOLE
- fi
- dep_tristate 'Support for user-space parallel port device drivers' CONFIG_PPDEV $CONFIG_PARPORT
+ dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
+ if [ "$CONFIG_PRINTER" != "n" ]; then
+ bool ' Support for console on line printer' CONFIG_LP_CONSOLE
+ fi
+ dep_tristate 'Support for user-space parallel port device drivers' CONFIG_PPDEV $CONFIG_PARPORT
fi
mainmenu_option next_comment
comment 'Mice'
tristate 'Bus Mouse Support' CONFIG_BUSMOUSE
if [ "$CONFIG_BUSMOUSE" != "n" ]; then
- dep_tristate 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE $CONFIG_BUSMOUSE
- dep_tristate 'Logitech busmouse support' CONFIG_LOGIBUSMOUSE $CONFIG_BUSMOUSE
- dep_tristate 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE $CONFIG_BUSMOUSE
- if [ "$CONFIG_ADB" = "y" ]; then
- dep_tristate 'Apple Desktop Bus mouse support' CONFIG_ADBMOUSE $CONFIG_BUSMOUSE
- fi
+ dep_tristate ' ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE $CONFIG_BUSMOUSE
+ dep_tristate ' Logitech busmouse support' CONFIG_LOGIBUSMOUSE $CONFIG_BUSMOUSE
+ dep_tristate ' Microsoft busmouse support' CONFIG_MS_BUSMOUSE $CONFIG_BUSMOUSE
+ if [ "$CONFIG_ADB" = "y" ]; then
+ dep_tristate ' Apple Desktop Bus mouse support' CONFIG_ADBMOUSE $CONFIG_BUSMOUSE
+ fi
fi
tristate 'Mouse Support (not serial and bus mice)' CONFIG_MOUSE
if [ "$CONFIG_MOUSE" != "n" ]; then
- bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE
- tristate 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE
- tristate 'PC110 digitizer pad support' CONFIG_PC110_PAD
+ bool ' PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE
+ tristate ' C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE
+ tristate ' PC110 digitizer pad support' CONFIG_PC110_PAD
fi
endmenu
tristate 'QIC-02 tape support' CONFIG_QIC02_TAPE
if [ "$CONFIG_QIC02_TAPE" != "n" ]; then
- bool 'Do you want runtime configuration for QIC-02' CONFIG_QIC02_DYNCONF
- if [ "$CONFIG_QIC02_DYNCONF" != "y" ]; then
- comment ' Edit configuration parameters in ./include/linux/tpqic02.h!'
- else
- comment ' Setting runtime QIC-02 configuration is done with qic02conf'
- comment ' from the tpqic02-support package. It is available at'
- comment ' metalab.unc.edu or ftp://titus.cfw.com/pub/Linux/util/'
- fi
- dep_tristate 'Zoran ZR36057/36060 support' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV
- dep_tristate ' Include support for Iomega Buz' CONFIG_VIDEO_BUZ $CONFIG_VIDEO_ZORAN
+ bool ' Do you want runtime configuration for QIC-02' CONFIG_QIC02_DYNCONF
+ if [ "$CONFIG_QIC02_DYNCONF" != "y" ]; then
+ comment ' Edit configuration parameters in ./include/linux/tpqic02.h!'
+ else
+ comment ' Setting runtime QIC-02 configuration is done with qic02conf'
+ comment ' from the tpqic02-support package. It is available at'
+ comment ' metalab.unc.edu or ftp://titus.cfw.com/pub/Linux/util/'
+ fi
fi
+mainmenu_option next_comment
+comment 'Watchdog Cards'
bool 'Watchdog Timer Support' CONFIG_WATCHDOG
if [ "$CONFIG_WATCHDOG" != "n" ]; then
- mainmenu_option next_comment
- comment 'Watchdog Cards'
- bool ' Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT
- tristate ' WDT Watchdog timer' CONFIG_WDT
- if [ "$CONFIG_WDT" != "n" ]; then
- bool ' WDT501 features' CONFIG_WDT_501
- if [ "$CONFIG_WDT_501" = "y" ]; then
+ bool ' Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT
+ tristate ' WDT Watchdog timer' CONFIG_WDT
+ if [ "$CONFIG_WDT" != "n" ]; then
+ bool ' WDT501 features' CONFIG_WDT_501
+ if [ "$CONFIG_WDT_501" = "y" ]; then
bool ' Fan Tachometer' CONFIG_WDT_501_FAN
- fi
- fi
- tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG
- tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG
- tristate ' Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT
- endmenu
+ fi
+ fi
+ tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG
+ tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG
+ tristate ' Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT
fi
+endmenu
tristate '/dev/nvram support' CONFIG_NVRAM
bool 'Enhanced Real Time Clock Support' CONFIG_RTC
if [ "$CONFIG_ALPHA_BOOK1" = "y" ]; then
- bool 'Tadpole ANA H8 Support' CONFIG_H8
+ bool 'Tadpole ANA H8 Support' CONFIG_H8
fi
mainmenu_option next_comment
tristate 'Video For Linux' CONFIG_VIDEO_DEV
if [ "$CONFIG_VIDEO_DEV" != "n" ]; then
- dep_tristate 'ADS Cadet AM/FM Tuner' CONFIG_RADIO_CADET $CONFIG_VIDEO_DEV
- dep_tristate 'AIMSlab RadioTrack (aka RadioReveal) support' CONFIG_RADIO_RTRACK $CONFIG_VIDEO_DEV
- if [ "$CONFIG_RADIO_RTRACK" = "y" ]; then
- hex ' RadioTrack i/o port (0x20f or 0x30f)' CONFIG_RADIO_RTRACK_PORT 20f
- fi
- dep_tristate 'AIMSlab RadioTrack II support' CONFIG_RADIO_RTRACK2 $CONFIG_VIDEO_DEV
- if [ "$CONFIG_RADIO_RTRACK2" = "y" ]; then
- hex ' RadioTrack II i/o port (0x20c or 0x30c)' CONFIG_RADIO_RTRACK2_PORT 30c
- fi
- dep_tristate 'Aztech/Packard Bell Radio' CONFIG_RADIO_AZTECH $CONFIG_VIDEO_DEV
- if [ "$CONFIG_RADIO_AZTECH" = "y" ]; then
- hex ' Aztech/Packard Bell I/O port (0x350 or 0x358)' CONFIG_RADIO_AZTECH_PORT 350
- fi
- dep_tristate 'GemTek Radio Card support' CONFIG_RADIO_GEMTEK $CONFIG_VIDEO_DEV
- if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then
- hex ' GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c
- fi
- dep_tristate 'Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV
- dep_tristate 'TerraTec ActiveRadio ISA Standalone' CONFIG_RADIO_TERRATEC $CONFIG_VIDEO_DEV
- if [ "$CONFIG_RADIO_TERRATEC" = "y" ]; then
- hex ' Terratec i/o port (normally 0x590)' CONFIG_RADIO_TERRATEC_PORT 590
- fi
- dep_tristate 'Trust FM radio card' CONFIG_RADIO_TRUST $CONFIG_VIDEO_DEV
- if [ "$CONFIG_RADIO_TRUST" = "y" ]; then
- hex ' Trust i/o port (usually 0x350 or 0x358)' CONFIG_RADIO_TRUST_PORT 350
- fi
- if [ "$CONFIG_PCI" != "n" ]; then
- dep_tristate 'BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV
- fi
- if [ "$CONFIG_PARPORT" != "n" ]; then
- dep_tristate 'Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT
- dep_tristate 'Colour QuickCam Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT
- fi
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- if [ "$CONFIG_SGI" = "y" ]; then
- dep_tristate 'SGI Vino Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_VINO $CONFIG_VIDEO_DEV
- fi
- fi
- dep_tristate 'Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV
- if [ "$CONFIG_PMAC" = "y" ]; then
- dep_tristate 'PlanB Video-In on PowerMac' CONFIG_VIDEO_PLANB $CONFIG_VIDEO_DEV
- fi
- dep_tristate 'SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV
- dep_tristate 'SF16FMI Radio' CONFIG_RADIO_SF16FMI $CONFIG_VIDEO_DEV
- if [ "$CONFIG_RADIO_SF16FMI" = "y" ]; then
- hex ' SF16FMI I/O port (0x284 or 0x384)' CONFIG_RADIO_SF16FMI_PORT 284
- fi
- dep_tristate 'Typhoon Radio (a.k.a. EcoRadio)' CONFIG_RADIO_TYPHOON $CONFIG_VIDEO_DEV
- if [ "$CONFIG_PROC_FS" = "y" ]; then
+ dep_tristate ' I2C on parallel port' CONFIG_I2C_PARPORT $CONFIG_PARPORT
+ comment 'Radio/Video Adapters'
+ dep_tristate ' ADS Cadet AM/FM Tuner' CONFIG_RADIO_CADET $CONFIG_VIDEO_DEV
+ dep_tristate ' AIMSlab RadioTrack (aka RadioReveal) support' CONFIG_RADIO_RTRACK $CONFIG_VIDEO_DEV
+ if [ "$CONFIG_RADIO_RTRACK" = "y" ]; then
+ hex ' RadioTrack i/o port (0x20f or 0x30f)' CONFIG_RADIO_RTRACK_PORT 20f
+ fi
+ dep_tristate ' AIMSlab RadioTrack II support' CONFIG_RADIO_RTRACK2 $CONFIG_VIDEO_DEV
+ if [ "$CONFIG_RADIO_RTRACK2" = "y" ]; then
+ hex ' RadioTrack II i/o port (0x20c or 0x30c)' CONFIG_RADIO_RTRACK2_PORT 30c
+ fi
+ dep_tristate ' Aztech/Packard Bell Radio' CONFIG_RADIO_AZTECH $CONFIG_VIDEO_DEV
+ if [ "$CONFIG_RADIO_AZTECH" = "y" ]; then
+ hex ' Aztech/Packard Bell I/O port (0x350 or 0x358)' CONFIG_RADIO_AZTECH_PORT 350
+ fi
+ if [ "$CONFIG_PCI" != "n" ]; then
+ dep_tristate ' BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV
+ fi
+ dep_tristate ' GemTek Radio Card support' CONFIG_RADIO_GEMTEK $CONFIG_VIDEO_DEV
+ if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then
+ hex ' GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c
+ fi
+ dep_tristate ' Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV
+ dep_tristate ' Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV
+ if [ "$CONFIG_PMAC" = "y" ]; then
+ dep_tristate ' PlanB Video-In on PowerMac' CONFIG_VIDEO_PLANB $CONFIG_VIDEO_DEV
+ fi
+ if [ "$CONFIG_PARPORT" != "n" ]; then
+ dep_tristate ' Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ dep_tristate ' QuickCam Colour Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT
+ fi
+ fi
+ dep_tristate ' SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV
+ dep_tristate ' SF16FMI Radio' CONFIG_RADIO_SF16FMI $CONFIG_VIDEO_DEV
+ if [ "$CONFIG_RADIO_SF16FMI" = "y" ]; then
+ hex ' SF16FMI I/O port (0x284 or 0x384)' CONFIG_RADIO_SF16FMI_PORT 284
+ fi
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ if [ "$CONFIG_SGI" = "y" ]; then
+ dep_tristate ' SGI Vino Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_VINO $CONFIG_VIDEO_DEV
+ fi
+ fi
+ dep_tristate ' TerraTec ActiveRadio ISA Standalone' CONFIG_RADIO_TERRATEC $CONFIG_VIDEO_DEV
+ if [ "$CONFIG_RADIO_TERRATEC" = "y" ]; then
+ hex ' Terratec i/o port (normally 0x590)' CONFIG_RADIO_TERRATEC_PORT 590
+ fi
+ dep_tristate ' Trust FM radio card' CONFIG_RADIO_TRUST $CONFIG_VIDEO_DEV
+ if [ "$CONFIG_RADIO_TRUST" = "y" ]; then
+ hex ' Trust i/o port (usually 0x350 or 0x358)' CONFIG_RADIO_TRUST_PORT 350
+ fi
+ dep_tristate ' Typhoon Radio (a.k.a. EcoRadio)' CONFIG_RADIO_TYPHOON $CONFIG_VIDEO_DEV
+ if [ "$CONFIG_PROC_FS" = "y" ]; then
if [ "$CONFIG_RADIO_TYPHOON" != "n" ]; then
- bool ' Support for /proc/radio-typhoon' CONFIG_RADIO_TYPHOON_PROC_FS
+ bool ' Support for /proc/radio-typhoon' CONFIG_RADIO_TYPHOON_PROC_FS
fi
- fi
- if [ "$CONFIG_RADIO_TYPHOON" = "y" ]; then
- hex ' Typhoon I/O port (0x316 or 0x336)' CONFIG_RADIO_TYPHOON_PORT 316
- int ' Typhoon frequency set when muting the device (kHz)' CONFIG_RADIO_TYPHOON_MUTEFREQ 87500
- fi
- dep_tristate 'Zoltrix Radio' CONFIG_RADIO_ZOLTRIX $CONFIG_VIDEO_DEV
- if [ "$CONFIG_RADIO_ZOLTRIX" = "y" ]; then
- hex ' ZOLTRIX I/O port (0x20c or 0x30c)' CONFIG_RADIO_ZOLTRIX_PORT 20c
- fi
- dep_tristate 'IIC on parallel port' CONFIG_I2C_PARPORT $CONFIG_PARPORT
+ fi
+ if [ "$CONFIG_RADIO_TYPHOON" = "y" ]; then
+ hex ' Typhoon I/O port (0x316 or 0x336)' CONFIG_RADIO_TYPHOON_PORT 316
+ int ' Typhoon frequency set when muting the device (kHz)' CONFIG_RADIO_TYPHOON_MUTEFREQ 87500
+ fi
+ dep_tristate ' Zoltrix Radio' CONFIG_RADIO_ZOLTRIX $CONFIG_VIDEO_DEV
+ if [ "$CONFIG_RADIO_ZOLTRIX" = "y" ]; then
+ hex ' ZOLTRIX I/O port (0x20c or 0x30c)' CONFIG_RADIO_ZOLTRIX_PORT 20c
+ fi
+ dep_tristate ' Zoran ZR36057/36060 support' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV
+ dep_tristate ' Include support for Iomega Buz' CONFIG_VIDEO_BUZ $CONFIG_VIDEO_ZORAN
fi
endmenu
tristate 'Joystick support' CONFIG_JOYSTICK
if [ "$CONFIG_JOYSTICK" != "n" ]; then
- source drivers/char/joystick/Config.in
+ source drivers/char/joystick/Config.in
fi
endmenu
comment 'Ftape, the floppy tape device driver'
tristate 'Ftape (QIC-80/Travan) support' CONFIG_FTAPE
if [ "$CONFIG_FTAPE" != "n" ]; then
- source drivers/char/ftape/Config.in
+ source drivers/char/ftape/Config.in
fi
endmenu
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM
- if [ "$CONFIG_DRM" = "y" ]; then
- dep_tristate ' 3dlabs GMX 2000' CONFIG_DRM_GAMMA m
- fi
+ bool 'Direct Rendering Manager (XFree86 DRI support) (EXPERIMENTAL)' CONFIG_DRM
+ if [ "$CONFIG_DRM" = "y" ]; then
+ dep_tristate ' 3dlabs GMX 2000' CONFIG_DRM_GAMMA m
+ fi
fi
endmenu
# ISDN device configuration
#
if [ "$CONFIG_INET" != "n" ]; then
- bool 'Support synchronous PPP' CONFIG_ISDN_PPP
- if [ "$CONFIG_ISDN_PPP" != "n" ]; then
- bool 'Use VJ-compression with synchronous PPP' CONFIG_ISDN_PPP_VJ
- bool 'Support generic MP (RFC 1717)' CONFIG_ISDN_MPP
- fi
+ bool ' Support synchronous PPP' CONFIG_ISDN_PPP
+ if [ "$CONFIG_ISDN_PPP" != "n" ]; then
+ bool ' Use VJ-compression with synchronous PPP' CONFIG_ISDN_PPP_VJ
+ bool ' Support generic MP (RFC 1717)' CONFIG_ISDN_MPP
+ fi
fi
-bool 'Support audio via ISDN' CONFIG_ISDN_AUDIO
+bool ' Support audio via ISDN' CONFIG_ISDN_AUDIO
if [ "$CONFIG_ISDN_AUDIO" != "n" ]; then
- bool 'Support AT-Fax Class 2 commands' CONFIG_ISDN_TTY_FAX
+ bool ' Support AT-Fax Class 2 commands' CONFIG_ISDN_TTY_FAX
fi
-bool 'Support isdn diversion services' CONFIG_ISDN_DIVERSION
-if [ "$CONFIG_X25" != "n" ]; then
- bool 'X.25 PLP on top of ISDN (EXPERIMENTAL)' CONFIG_ISDN_X25
+bool ' Support isdn diversion services' CONFIG_ISDN_DIVERSION
+if [ "$CONFIG_X25" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ bool ' X.25 PLP on top of ISDN (EXPERIMENTAL)' CONFIG_ISDN_X25
fi
-dep_tristate 'ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN
-dep_tristate 'isdnloop support' CONFIG_ISDN_DRV_LOOP $CONFIG_ISDN
-dep_tristate 'PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN
-dep_tristate 'HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG_ISDN
+dep_tristate ' ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN
+dep_tristate ' isdnloop support' CONFIG_ISDN_DRV_LOOP $CONFIG_ISDN
+dep_tristate ' PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN
+dep_tristate ' HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG_ISDN
if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
- bool 'HiSax Support for EURO/DSS1' CONFIG_HISAX_EURO
- if [ "$CONFIG_HISAX_EURO" != "n" ]; then
- bool 'Support for german chargeinfo' CONFIG_DE_AOC
- bool 'Disable sending complete' CONFIG_HISAX_NO_SENDCOMPLETE
- bool 'Disable sending low layer compatibility' CONFIG_HISAX_NO_LLC
- fi
- bool 'HiSax Support for german 1TR6' CONFIG_HISAX_1TR6
- bool 'HiSax Support for Teles 16.0/8.0' CONFIG_HISAX_16_0
- bool 'HiSax Support for Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
- bool 'HiSax Support for Teles PCI' CONFIG_HISAX_TELESPCI
- bool 'HiSax Support for Teles S0Box' CONFIG_HISAX_S0BOX
- bool 'HiSax Support for AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1
- bool 'HiSax Support for AVM PnP/PCI (Fritz!PnP/PCI)' CONFIG_HISAX_FRITZPCI
- bool 'HiSax Support for AVM A1 PCMCIA (Fritz)' CONFIG_HISAX_AVM_A1_PCMCIA
- bool 'HiSax Support for Elsa cards' CONFIG_HISAX_ELSA
- bool 'HiSax Support for ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2
- bool 'HiSax Support for Eicon.Diehl Diva cards' CONFIG_HISAX_DIEHLDIVA
- bool 'HiSax Support for ASUSCOM cards' CONFIG_HISAX_ASUSCOM
- bool 'HiSax Support for TELEINT cards' CONFIG_HISAX_TELEINT
- bool 'HiSax Support for HFC-S based cards' CONFIG_HISAX_HFCS
- bool 'HiSax Support for Sedlbauer cards' CONFIG_HISAX_SEDLBAUER
- bool 'HiSax Support for USR Sportster internal TA' CONFIG_HISAX_SPORTSTER
- bool 'HiSax Support for MIC card' CONFIG_HISAX_MIC
- bool 'HiSax Support for NETjet card' CONFIG_HISAX_NETJET
- bool 'HiSax Support for Niccy PnP/PCI card' CONFIG_HISAX_NICCY
- bool 'HiSax Support for Siemens I-Surf card' CONFIG_HISAX_ISURF
- bool 'HiSax Support for HST Saphir card' CONFIG_HISAX_HSTSAPHIR
- bool 'HiSax Support for Telekom A4T card' CONFIG_HISAX_BKM_A4T
- bool 'HiSax Support for Scitel Quadro card' CONFIG_HISAX_SCT_QUADRO
- bool 'HiSax Support for Gazel cards' CONFIG_HISAX_GAZEL
- bool 'HiSax Support for HFC PCI-Bus cards' CONFIG_HISAX_HFC_PCI
- if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
- bool 'HiSax Support for Winbond W6692 based cards (EXPERIMENTAL)' CONFIG_HISAX_W6692
-# bool 'HiSax Support for TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU
- if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
- bool 'HiSax Support for Am7930' CONFIG_HISAX_AMD7930
- fi
- fi
+ bool ' HiSax Support for EURO/DSS1' CONFIG_HISAX_EURO
+ if [ "$CONFIG_HISAX_EURO" != "n" ]; then
+ bool ' Support for german chargeinfo' CONFIG_DE_AOC
+ bool ' Disable sending complete' CONFIG_HISAX_NO_SENDCOMPLETE
+ bool ' Disable sending low layer compatibility' CONFIG_HISAX_NO_LLC
+ fi
+ bool ' HiSax Support for german 1TR6' CONFIG_HISAX_1TR6
+ bool ' HiSax Support for Teles 16.0/8.0' CONFIG_HISAX_16_0
+ bool ' HiSax Support for Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
+ bool ' HiSax Support for Teles PCI' CONFIG_HISAX_TELESPCI
+ bool ' HiSax Support for Teles S0Box' CONFIG_HISAX_S0BOX
+ bool ' HiSax Support for AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1
+ bool ' HiSax Support for AVM PnP/PCI (Fritz!PnP/PCI)' CONFIG_HISAX_FRITZPCI
+ bool ' HiSax Support for AVM A1 PCMCIA (Fritz)' CONFIG_HISAX_AVM_A1_PCMCIA
+ bool ' HiSax Support for Elsa cards' CONFIG_HISAX_ELSA
+ bool ' HiSax Support for ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2
+ bool ' HiSax Support for Eicon.Diehl Diva cards' CONFIG_HISAX_DIEHLDIVA
+ bool ' HiSax Support for ASUSCOM cards' CONFIG_HISAX_ASUSCOM
+ bool ' HiSax Support for TELEINT cards' CONFIG_HISAX_TELEINT
+ bool ' HiSax Support for HFC-S based cards' CONFIG_HISAX_HFCS
+ bool ' HiSax Support for Sedlbauer cards' CONFIG_HISAX_SEDLBAUER
+ bool ' HiSax Support for USR Sportster internal TA' CONFIG_HISAX_SPORTSTER
+ bool ' HiSax Support for MIC card' CONFIG_HISAX_MIC
+ bool ' HiSax Support for NETjet card' CONFIG_HISAX_NETJET
+ bool ' HiSax Support for Niccy PnP/PCI card' CONFIG_HISAX_NICCY
+ bool ' HiSax Support for Siemens I-Surf card' CONFIG_HISAX_ISURF
+ bool ' HiSax Support for HST Saphir card' CONFIG_HISAX_HSTSAPHIR
+ bool ' HiSax Support for Telekom A4T card' CONFIG_HISAX_BKM_A4T
+ bool ' HiSax Support for Scitel Quadro card' CONFIG_HISAX_SCT_QUADRO
+ bool ' HiSax Support for Gazel cards' CONFIG_HISAX_GAZEL
+ bool ' HiSax Support for HFC PCI-Bus cards' CONFIG_HISAX_HFC_PCI
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ bool ' HiSax Support for Winbond W6692 based cards (EXPERIMENTAL)' CONFIG_HISAX_W6692
+# bool ' HiSax Support for TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU
+ if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+ bool ' HiSax Support for Am7930' CONFIG_HISAX_AMD7930
+ fi
+ fi
fi
-if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
- dep_tristate 'Spellcaster support (EXPERIMENTAL)' CONFIG_ISDN_DRV_SC $CONFIG_ISDN
- dep_tristate 'IBM Active 2000 support (EXPERIMENTAL)' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ dep_tristate ' Spellcaster support (EXPERIMENTAL)' CONFIG_ISDN_DRV_SC $CONFIG_ISDN
+ dep_tristate ' IBM Active 2000 support (EXPERIMENTAL)' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN
fi
-dep_tristate 'Eicon.Diehl active card support' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN
+dep_tristate ' Eicon.Diehl active card support' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN
if [ "$CONFIG_ISDN_DRV_EICON" != "n" ]; then
- bool 'Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA
+ bool ' Eicon S, SX, SCOM, Quadro, S2M support' CONFIG_ISDN_DRV_EICON_ISA
fi
-dep_tristate 'AVM CAPI2.0 support' CONFIG_ISDN_DRV_AVMB1 $CONFIG_ISDN
+dep_tristate ' AVM CAPI2.0 support' CONFIG_ISDN_DRV_AVMB1 $CONFIG_ISDN
if [ "$CONFIG_ISDN_DRV_AVMB1" != "n" ]; then
- bool 'AVM B1 ISA support' CONFIG_ISDN_DRV_AVMB1_B1ISA
- bool 'AVM B1 PCI support' CONFIG_ISDN_DRV_AVMB1_B1PCI
- bool 'AVM T1/T1-B ISA support' CONFIG_ISDN_DRV_AVMB1_T1ISA
- bool 'AVM B1/M1/M2 PCMCIA support' CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
- bool 'AVM T1/T1-B PCI support' CONFIG_ISDN_DRV_AVMB1_T1PCI
- bool 'Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
+ bool ' AVM B1 ISA support' CONFIG_ISDN_DRV_AVMB1_B1ISA
+ bool ' AVM B1 PCI support' CONFIG_ISDN_DRV_AVMB1_B1PCI
+ bool ' AVM T1/T1-B ISA support' CONFIG_ISDN_DRV_AVMB1_T1ISA
+ bool ' AVM B1/M1/M2 PCMCIA support' CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
+ bool ' AVM T1/T1-B PCI support' CONFIG_ISDN_DRV_AVMB1_T1PCI
+ bool ' Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
fi
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kmod.h>
+#include <linux/init.h>
#include <linux/list.h>
#include <linux/netdevice.h>
#include <linux/poll.h>
struct buffer_head * bh;
struct bfs_super_block * bfs_sb;
struct inode * inode;
- int i, imap_len;
+ int i, imap_len, bmap_len;
MOD_INC_USE_COUNT;
lock_super(s);
s->su_lasti = (bfs_sb->s_start - BFS_BSIZE)/sizeof(struct bfs_inode)
+ BFS_ROOT_INO - 1;
- s->su_bmap = kmalloc(sizeof(struct bfs_bmap) * s->su_lasti, GFP_KERNEL);
+ bmap_len = sizeof(struct bfs_bmap) * s->su_lasti;
+ s->su_bmap = kmalloc(bmap_len, GFP_KERNEL);
if (!s->su_bmap)
goto out;
+ memset(s->su_bmap, 0, bmap_len);
imap_len = s->su_lasti/8 + 1;
s->su_imap = kmalloc(imap_len, GFP_KERNEL);
if (!s->su_imap) {
case 1:
offset += file->f_pos;
}
+ if (offset<0)
+ return -EINVAL;
if (((unsigned long long) offset >> 32) != 0) {
if (offset > ext2_max_sizes[EXT2_BLOCK_SIZE_BITS(inode->i_sb)])
return -EINVAL;
O_TARGET := proc.o
O_OBJS := inode.o root.o base.o generic.o array.o \
- kmsg.o proc_tty.o sysvipc.o proc_misc.o kcore.o
+ kmsg.o proc_tty.o proc_misc.o kcore.o
ifdef CONFIG_OMIRR
O_OBJS := $(O_OBJS) omirr.o
endif
-Inode allocations in the proc-fs (hex-numbers):
+Current inode allocations in the proc-fs (hex-numbers):
00000000 reserved
- 00000001-00000fff static entries
+ 00000001-00000fff static entries (goners)
001 root-ino
- 002 load-avg
- 003 uptime
- ...
- 080 net/*
- ...
100 scsi/*
...
- xxx mca/*
- ...
- yyy bus/*
- ...
fff end
00001000-00001fff dynamic entries
-
00002000-00002fff openprom entries
-
0001xxxx-7fffxxxx pid-dir entries for pid 1-7fff
- 0000 unused
- 0001 unused
- 0002 pid
- 0003 pid/status
- ...
- 0008 pid/fd
- ...
- 00xx-00ff unused
- 01xx pid/fd/* for fd 0-ff
- ...
- 01ff end
- 0200-ffff unused
-
80000000-ffffffff unused
-
-
-New allocation:
-
- 00000000-0000ffff unchanged
-
- 0001xxxx-7fffxxxx pid-dir entries for pid 1-7fff
- 0000-00ff unchanged
- 0100-7fff unused
- 8000-ffff pid/fd/* for fd 0-7fff
-
- 80000000-ffffffff unchanged
+Goals:
+ a) the only static inumber that will stay is root's.
+ b) scsi should go dynamic.
+ c) once we'll split the thing into several virtual filesystems we
+ will get rid of magical ranges (and this file, BTW).
* store an ELF coredump header in the supplied buffer
* - assume the memory image is the size specified
*/
-static void elf_kcore_store_hdr(char *bufp, size_t size, off_t dataoff)
+static void elf_kcore_store_hdr(char *bufp)
{
struct elf_prstatus prstatus; /* NT_PRSTATUS */
struct elf_prpsinfo psinfo; /* NT_PRPSINFO */
/* acquire an ELF header block from the buffer */
elf = (struct elfhdr *) bufp;
- bufp += sizeof(*elf);
- offset += sizeof(*elf);
+ bufp += sizeof(struct elfhdr);
+ offset += sizeof(struct elfhdr);
/* set up header */
memcpy(elf->e_ident,ELFMAG,SELFMAG);
elf->e_ident[EI_CLASS] = ELF_CLASS;
elf->e_ident[EI_DATA] = ELF_DATA;
elf->e_ident[EI_VERSION]= EV_CURRENT;
- memset(elf->e_ident+EI_PAD,0,EI_NIDENT-EI_PAD);
+ memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
elf->e_type = ET_CORE;
elf->e_machine = ELF_ARCH;
elf->e_version = EV_CURRENT;
elf->e_entry = 0;
- elf->e_phoff = sizeof(*elf);
+ elf->e_phoff = sizeof(struct elfhdr);
elf->e_shoff = 0;
elf->e_flags = 0;
- elf->e_ehsize = sizeof(*elf);
+ elf->e_ehsize = sizeof(struct elfhdr);
elf->e_phentsize= sizeof(struct elf_phdr);
- elf->e_phnum = 2; /* no. of segments */
+ elf->e_phnum = 1; /* no. of segments = 1 + Nmodules */
elf->e_shentsize= 0;
elf->e_shnum = 0;
elf->e_shstrndx = 0;
/* acquire an ELF program header blocks from the buffer for notes */
nhdr = (struct elf_phdr *) bufp;
- bufp += sizeof(*nhdr);
- offset += sizeof(*nhdr);
+ bufp += sizeof(struct elf_phdr);
+ offset += sizeof(struct elf_phdr);
/* store program headers for notes dump */
nhdr->p_type = PT_NOTE;
nhdr->p_offset = 0;
nhdr->p_vaddr = 0;
nhdr->p_paddr = 0;
+ nhdr->p_filesz = 0;
nhdr->p_memsz = 0;
nhdr->p_flags = 0;
nhdr->p_align = 0;
/* acquire an ELF program header blocks from the buffer for data */
dhdr = (struct elf_phdr *) bufp;
- bufp += sizeof(*dhdr);
- offset += sizeof(*dhdr);
+ bufp += sizeof(struct elf_phdr);
+ offset += sizeof(struct elf_phdr);
/* store program headers for data dump */
dhdr->p_type = PT_LOAD;
dhdr->p_flags = PF_R|PF_W|PF_X;
- dhdr->p_offset = dataoff;
+ dhdr->p_offset = PAGE_SIZE;
dhdr->p_vaddr = PAGE_OFFSET;
dhdr->p_paddr = __pa(PAGE_OFFSET);
- dhdr->p_filesz = size;
- dhdr->p_memsz = size;
+ dhdr->p_filesz = ((unsigned long)high_memory - PAGE_OFFSET + PAGE_SIZE);
+ dhdr->p_memsz = ((unsigned long)high_memory - PAGE_OFFSET + PAGE_SIZE);
dhdr->p_align = PAGE_SIZE;
+#ifdef CONFIG_MODULES
+ {
+ struct module *m;
+ for (m=module_list; m; m=m->next) {
+ dhdr = (struct elf_phdr *) bufp;
+ bufp += sizeof(struct elf_phdr);
+ offset += sizeof(struct elf_phdr);
+
+ dhdr->p_type = PT_LOAD;
+ dhdr->p_flags = PF_R|PF_W|PF_X;
+ dhdr->p_offset = (unsigned long)m - PAGE_OFFSET + PAGE_SIZE;
+ dhdr->p_vaddr = (unsigned long)m;
+ dhdr->p_paddr = __pa(m);
+ dhdr->p_filesz = m->size;
+ dhdr->p_memsz = m->size;
+ dhdr->p_align = 0;
+ elf->e_phnum++;
+ }
+ }
+#endif
+
/*
* Set up the notes in similar form to SVR4 core dumps made
* with info from their /proc.
*/
nhdr->p_offset = offset;
- nhdr->p_filesz = 0;
/* set up the process status */
notes[0].name = "CORE";
/* create a header */
memset(page,0,PAGE_SIZE);
- elf_kcore_store_hdr(page,size-PAGE_SIZE,PAGE_SIZE);
+ elf_kcore_store_hdr(page);
/* copy data to the users buffer */
copy_to_user(buffer,page,tsz);
&proc_root, NULL
};
-struct proc_dir_entry *proc_net, *proc_bus, *proc_sysvipc,
- *proc_root_fs, *proc_root_driver;
+struct proc_dir_entry *proc_net, *proc_bus, *proc_root_fs, *proc_root_driver;
#ifdef CONFIG_MCA
struct proc_dir_entry *proc_mca;
return PROC_DYNAMIC_FIRST + i;
}
+int proc_readlink(struct dentry * dentry, char * buffer, int buflen)
+{
+ struct inode *inode = dentry->d_inode;
+ struct proc_dir_entry * de;
+ char *page;
+ int len = 0;
+
+ de = (struct proc_dir_entry *) inode->u.generic_ip;
+ if (!de)
+ return -ENOENT;
+ if (!(page = (char*) __get_free_page(GFP_KERNEL)))
+ return -ENOMEM;
+
+ if (de->readlink_proc)
+ len = de->readlink_proc(de, page);
+
+ if (len > buflen)
+ len = buflen;
+
+ copy_to_user(buffer, page, len);
+ free_page((unsigned long) page);
+ return len;
+}
+
+struct dentry * proc_follow_link(struct dentry * dentry, struct dentry *base, unsigned int follow)
+{
+ struct inode *inode = dentry->d_inode;
+ struct proc_dir_entry * de;
+ char *page;
+ struct dentry *d;
+ int len = 0;
+
+ de = (struct proc_dir_entry *) inode->u.generic_ip;
+ if (!(page = (char*) __get_free_page(GFP_KERNEL)))
+ return NULL;
+
+ if (de->readlink_proc)
+ len = de->readlink_proc(de, page);
+
+ d = lookup_dentry(page, base, follow);
+ free_page((unsigned long) page);
+ return d;
+}
+
+static struct inode_operations proc_link_inode_operations = {
+ NULL, /* no file-ops */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ proc_readlink, /* readlink */
+ proc_follow_link, /* follow_link */
+ NULL, /* get_block */
+ NULL, /* readpage */
+ NULL, /* writepage */
+ NULL, /* flushpage */
+ NULL, /* truncate */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL /* revalidate */
+};
+
int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
{
int i;
return lookup_dentry(tmp, base, follow);
}
-int proc_readlink(struct dentry * dentry, char * buffer, int buflen)
-{
- struct inode *inode = dentry->d_inode;
- struct proc_dir_entry * de;
- char *page;
- int len = 0;
-
- de = (struct proc_dir_entry *) inode->u.generic_ip;
- if (!de)
- return -ENOENT;
- if (!(page = (char*) __get_free_page(GFP_KERNEL)))
- return -ENOMEM;
-
- if (de->readlink_proc)
- len = de->readlink_proc(de, page);
-
- if (len > buflen)
- len = buflen;
-
- copy_to_user(buffer, page, len);
- free_page((unsigned long) page);
- return len;
-}
-
-struct dentry * proc_follow_link(struct dentry * dentry, struct dentry *base, unsigned int follow)
-{
- struct inode *inode = dentry->d_inode;
- struct proc_dir_entry * de;
- char *page;
- struct dentry *d;
- int len = 0;
-
- de = (struct proc_dir_entry *) inode->u.generic_ip;
- if (!(page = (char*) __get_free_page(GFP_KERNEL)))
- return NULL;
-
- if (de->readlink_proc)
- len = de->readlink_proc(de, page);
-
- d = lookup_dentry(page, base, follow);
- free_page((unsigned long) page);
- return d;
-}
-
static struct inode_operations proc_self_inode_operations = {
NULL, /* no file-ops */
NULL, /* create */
NULL /* revalidate */
};
-static struct inode_operations proc_link_inode_operations = {
- NULL, /* no file-ops */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- proc_readlink, /* readlink */
- proc_follow_link, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
-
static struct proc_dir_entry proc_root_self = {
0, 4, "self",
S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, 1, 0, 0,
proc_register(&proc_root, &proc_root_self);
proc_net = create_proc_entry("net", S_IFDIR, 0);
#ifdef CONFIG_SYSVIPC
- proc_sysvipc = create_proc_entry("sysvipc", S_IFDIR, 0);
+ create_proc_entry("sysvipc", S_IFDIR, 0);
#endif
#ifdef CONFIG_SYSCTL
proc_sys_root = create_proc_entry("sys", S_IFDIR, 0);
+++ /dev/null
-/*
- * linux/fs/proc/sysvipc.c
- *
- * Copyright (c) 1999 Dragos Acostachioaie
- *
- * This code is derived from linux/fs/proc/generic.c,
- * which is Copyright (C) 1991, 1992 Linus Torvalds.
- *
- * /proc/sysvipc directory handling functions
- */
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/mm.h>
-
-#include <asm/uaccess.h>
-
-#ifndef MIN
-#define MIN(a,b) (((a) < (b)) ? (a) : (b))
-#endif
-
-/* 4K page size but our output routines use some slack for overruns */
-#define PROC_BLOCK_SIZE (3*1024)
-
-static ssize_t
-proc_sysvipc_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos)
-{
- struct inode * inode = file->f_dentry->d_inode;
- char *page;
- ssize_t retval=0;
- int eof=0;
- ssize_t n, count;
- char *start;
- struct proc_dir_entry * dp;
-
- dp = (struct proc_dir_entry *) inode->u.generic_ip;
- if (!(page = (char*) __get_free_page(GFP_KERNEL)))
- return -ENOMEM;
-
- while ((nbytes > 0) && !eof)
- {
- count = MIN(PROC_BLOCK_SIZE, nbytes);
-
- start = NULL;
- if (dp->get_info) {
- /*
- * Handle backwards compatibility with the old net
- * routines.
- *
- * XXX What gives with the file->f_flags & O_ACCMODE
- * test? Seems stupid to me....
- */
- n = dp->get_info(page, &start, *ppos, count,
- (file->f_flags & O_ACCMODE) == O_RDWR);
- if (n < count)
- eof = 1;
- } else if (dp->read_proc) {
- n = dp->read_proc(page, &start, *ppos,
- count, &eof, dp->data);
- } else
- break;
-
- if (!start) {
- /*
- * For proc files that are less than 4k
- */
- start = page + *ppos;
- n -= *ppos;
- if (n <= 0)
- break;
- if (n > count)
- n = count;
- }
- if (n == 0)
- break; /* End of file */
- if (n < 0) {
- if (retval == 0)
- retval = n;
- break;
- }
-
- /* This is a hack to allow mangling of file pos independent
- * of actual bytes read. Simply place the data at page,
- * return the bytes, and set `start' to the desired offset
- * as an unsigned int. - Paul.Russell@rustcorp.com.au
- */
- n -= copy_to_user(buf, start < page ? page : start, n);
- if (n == 0) {
- if (retval == 0)
- retval = -EFAULT;
- break;
- }
-
- *ppos += start < page ? (long)start : n; /* Move down the file */
- nbytes -= n;
- buf += n;
- retval += n;
- }
- free_page((unsigned long) page);
- return retval;
-}
-
-static struct file_operations proc_sysvipc_operations = {
- NULL, /* lseek */
- proc_sysvipc_read, /* read */
- NULL, /* write */
- NULL, /* readdir */
- NULL, /* poll */
- NULL, /* ioctl */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* no special release code */
- NULL /* can't fsync */
-};
-
-/*
- * proc directories can do almost nothing..
- */
-struct inode_operations proc_sysvipc_inode_operations = {
- &proc_sysvipc_operations, /* default net file-ops */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
* exposed a problem in readdir
* 2.1.107 code-freeze spellchecker run
* Aug 1998 2.1.118+ VFS changes
+ * Sep 1998 2.1.122 another VFS change (follow_link)
+ * Apr 1999 2.2.7 no more EBADF checking in
+ * lookup/readdir, use ERR_PTR
+ * Jun 1999 2.3.6 d_alloc_root use changed
+ * 2.3.9 clean up usage of ENOENT/negative
+ * dentries in lookup
+ * clean up page flags setting
+ * (error, uptodate, locking) in
+ * in readpage
+ * use init_special_inode for
+ * fifos/sockets (and streamline) in
+ * read_inode, fix _ops table order
+ * Aug 1999 2.3.16 __initfunc() => __init change
+ * Oct 1999 2.3.24 page->owner hack obsoleted
+ * Nov 1999 2.3.27 2.3.25+ page->offset => index change
*/
/* todo:
get_page(page);
buf = page_address(page);
- offset = page->offset;
+ /* 32 bit warning -- but not for us :) */
+ offset = page->index << PAGE_CACHE_SHIFT;
if (offset < inode->i_size) {
avail = inode->i_size-offset;
readlen = min(avail, PAGE_SIZE);
#define IPC_UNUSED ((void *) -1)
#define IPC_NOID ((void *) -2) /* being allocated/destroyed */
+#define IPCMNI 32768 /* <= MAX_INT limit for ipc arrays (including sysctl changes) */
+
#endif /* __KERNEL__ */
#endif /* _LINUX_IPC_H */
unsigned short msgseg;
};
-#define MSGMNI 128 /* <= 32768 */ /* max # of msg queue identifiers */
-#define MSGMAX 4056 /* <= 4056 (?)*/ /* max size of message (bytes) */
-#define MSGMNB 16384 /* <= MAX_INT */ /* default max size of a message queue */
+#define MSGMNI 128 /* <= IPCMNI */ /* max # of msg queue identifiers */
+#define MSGMAX 8192 /* <= INT_MAX */ /* max size of message (bytes) */
+#define MSGMNB 16384 /* <= INT_MAX */ /* default max size of a message queue */
/* unused */
#define MSGPOOL (MSGMNI*MSGMNB/1024) /* size in kilobytes of message pool */
PROC_SCSI_LAST = (PROC_SCSI_FILE + 16) /* won't ever see more than */
}; /* 16 HBAs in one machine */
-enum mca_directory_inos {
- PROC_MCA_MACHINE = (PROC_SCSI_LAST+1),
- PROC_MCA_REGISTERS,
- PROC_MCA_VIDEO,
- PROC_MCA_SCSI,
- PROC_MCA_SLOT, /* the 8 adapter slots */
- PROC_MCA_LAST = (PROC_MCA_SLOT + 8)
-};
-
/* Finally, the dynamically allocatable proc entries are reserved: */
#define PROC_DYNAMIC_FIRST 4096
extern struct proc_dir_entry *proc_scsi;
extern struct proc_dir_entry proc_sys;
extern struct proc_dir_entry proc_openprom;
-extern struct proc_dir_entry proc_pid;
-extern struct proc_dir_entry proc_pid_fd;
extern struct proc_dir_entry *proc_mca;
extern struct proc_dir_entry *proc_bus;
-extern struct proc_dir_entry *proc_sysvipc;
extern struct proc_dir_entry *proc_root_driver;
extern struct proc_dir_entry proc_root_kcore;
return (p == NULL) ? -1 : 0;
}
-
-
extern struct super_block *proc_super_blocks;
extern struct dentry_operations proc_dentry_operations;
extern struct super_block *proc_read_super(struct super_block *,void *,int);
extern struct inode_operations proc_dir_inode_operations;
extern struct inode_operations proc_file_inode_operations;
-extern struct inode_operations proc_netdir_inode_operations;
extern struct inode_operations proc_openprom_inode_operations;
-extern struct inode_operations proc_mem_inode_operations;
extern struct inode_operations proc_sys_inode_operations;
extern struct inode_operations proc_kcore_inode_operations;
extern struct inode_operations proc_profile_inode_operations;
extern struct inode_operations proc_kmsg_inode_operations;
-extern struct inode_operations proc_link_inode_operations;
-extern struct inode_operations proc_fd_inode_operations;
#if CONFIG_AP1000
extern struct inode_operations proc_ringbuf_inode_operations;
#endif
extern struct inode_operations proc_omirr_inode_operations;
extern struct inode_operations proc_ppc_htab_inode_operations;
-extern struct inode_operations proc_sysvipc_inode_operations;
/*
* proc_tty.c
remove_proc_entry(name,proc_net);
}
-extern inline int proc_net_register(struct proc_dir_entry * x)
-{
- return proc_register(proc_net, x);
-}
-
-extern inline int proc_net_unregister(int x)
-{
- return proc_unregister(proc_net, x);
-}
-
#else
extern inline int proc_register(struct proc_dir_entry *a, struct proc_dir_entry *b) { return 0; }
extern inline struct proc_dir_entry *proc_net_create(const char *name, mode_t mode,
get_info_t *get_info) {return NULL;}
extern inline void proc_net_remove(const char *name) {}
-extern inline int proc_net_register(struct proc_dir_entry * x) { return 0; }
-extern inline int proc_net_unregister(int x) { return 0; }
extern inline int proc_scsi_register(struct proc_dir_entry *b, struct proc_dir_entry *c) { return 0; }
extern inline int proc_scsi_unregister(struct proc_dir_entry *a, int x) { return 0; }
int semaem;
};
-#define SEMMNI 128 /* <= 32767 max # of semaphore identifiers */
-#define SEMMSL 250 /* <= 512 max num of semaphores per id */
-#define SEMMNS (SEMMNI*SEMMSL) /* <= MAX_INT max # of semaphores in system */
-#define SEMOPM 32 /* <= 160 max num of ops per semop call */
+#define SEMMNI 128 /* <= IPCMNI max # of semaphore identifiers */
+#define SEMMSL 250 /* <= 8 000 max num of semaphores per id */
+#define SEMMNS (SEMMNI*SEMMSL) /* <= INT_MAX max # of semaphores in system */
+#define SEMOPM 32 /* <= 1 000 max num of ops per semop call */
#define SEMVMX 32767 /* <= 32767 semaphore maximum value */
/* unused */
KERN_MSGMNB=36, /* int: Maximum message queue size */
KERN_MSGPOOL=37, /* int: Maximum system message pool size */
KERN_SYSRQ=38, /* int: Sysreq enable */
- KERN_MAX_THREADS=39, /* int: Maximum nr of threads in the system */
+ KERN_MAX_THREADS=39, /* int: Maximum nr of threads in the system */
KERN_RANDOM=40, /* Random driver */
- KERN_SHMALL=41 /* int: Maximum size of shared memory */
+ KERN_SHMALL=41, /* int: Maximum size of shared memory */
+ KERN_MSGMNI=42, /* int: msg queue identifiers */
+ KERN_SEM=43 /* int: sysv semaphore limits */
};
* /proc/sysvipc/msg support (c) 1999 Dragos Acostachioaie <dragos@iname.com>
*
* mostly rewritten, threaded and wake-one semantics added
+ * MSGMAX limit removed, sysctl's added
* (c) 1999 Manfred Spraul <manfreds@colorfullife.com>
*/
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/list.h>
-
#include <asm/uaccess.h>
+#include "util.h"
+
+/* sysctl: */
+int msg_ctlmax = MSGMAX;
+int msg_ctlmnb = MSGMNB;
+int msg_ctlmni = MSGMNI;
-#define USHRT_MAX 0xffff
-/* one ms_receiver structure for each sleeping receiver */
+/* one msg_receiver structure for each sleeping receiver */
struct msg_receiver {
struct list_head r_list;
struct task_struct* r_tsk;
struct msg_msg* volatile r_msg;
};
+/* one msg_sender for each sleeping sender */
+struct msg_sender {
+ struct list_head list;
+ struct task_struct* tsk;
+};
+
+struct msg_msgseg {
+ struct msg_msgseg* next;
+ /* the next part of the message follows immediately */
+};
/* one msg_msg structure for each message */
struct msg_msg {
struct list_head m_list;
long m_type;
int m_ts; /* message text size */
+ struct msg_msgseg* next;
/* the actual message follows immediately */
};
+#define DATALEN_MSG (PAGE_SIZE-sizeof(struct msg_msg))
+#define DATALEN_SEG (PAGE_SIZE-sizeof(struct msg_msgseg))
/* one msq_queue structure for each present queue on the system */
struct msg_queue {
struct list_head q_messages;
struct list_head q_receivers;
- wait_queue_head_t q_rwait;
-};
-
-/* one msq_array structure for each possible queue on the system */
-struct msg_array {
- spinlock_t lock;
- struct msg_queue* q;
+ struct list_head q_senders;
};
#define SEARCH_ANY 1
#define SEARCH_NOTEQUAL 3
#define SEARCH_LESSEQUAL 4
-static DECLARE_MUTEX(msg_lock);
-static struct msg_array msg_que[MSGMNI];
-
-static unsigned short msg_seq = 0;
-static int msg_used_queues = 0;
-static int msg_max_id = -1;
-
static atomic_t msg_bytes = ATOMIC_INIT(0);
static atomic_t msg_hdrs = ATOMIC_INIT(0);
+static struct ipc_ids msg_ids;
+
+#define msg_lock(id) ((struct msg_queue*)ipc_lock(&msg_ids,id))
+#define msg_unlock(id) ipc_unlock(&msg_ids,id)
+#define msg_rmid(id) ((struct msg_queue*)ipc_rmid(&msg_ids,id))
+#define msg_checkid(msq, msgid) \
+ ipc_checkid(&msg_ids,&msq->q_perm,msgid)
+#define msg_buildid(id, seq) \
+ ipc_buildid(&msg_ids, id, seq)
+
static void freeque (int id);
static int newque (key_t key, int msgflg);
-static int findkey (key_t key);
#ifdef CONFIG_PROC_FS
static int sysvipc_msg_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
#endif
-/* implemented in ipc/util.c, thread-safe */
-extern int ipcperms (struct ipc_perm *ipcp, short msgflg);
-
void __init msg_init (void)
{
- int id;
+ ipc_init_ids(&msg_ids,msg_ctlmni);
- for (id = 0; id < MSGMNI; id++) {
- msg_que[id].lock = SPIN_LOCK_UNLOCKED;
- msg_que[id].q = NULL;
- }
#ifdef CONFIG_PROC_FS
create_proc_read_entry("sysvipc/msg", 0, 0, sysvipc_msg_read_proc, NULL);
#endif
}
-static int findkey (key_t key)
-{
- int id;
- struct msg_queue *msq;
-
- for (id = 0; id <= msg_max_id; id++) {
- msq = msg_que[id].q;
- if(msq == NULL)
- continue;
- if (key == msq->q_perm.key)
- return id;
- }
- return -1;
-}
-
static int newque (key_t key, int msgflg)
{
int id;
struct msg_queue *msq;
- struct ipc_perm *ipcp;
-
- for (id = 0; id < MSGMNI; id++) {
- if (msg_que[id].q == NULL)
- break;
- }
- if(id == MSGMNI)
- return -ENOSPC;
msq = (struct msg_queue *) kmalloc (sizeof (*msq), GFP_KERNEL);
if (!msq)
return -ENOMEM;
-
- ipcp = &msq->q_perm;
- ipcp->mode = (msgflg & S_IRWXUGO);
- ipcp->key = key;
- ipcp->cuid = ipcp->uid = current->euid;
- ipcp->gid = ipcp->cgid = current->egid;
-
- /* ipcp->seq*MSGMNI must be a positive integer.
- * this limits MSGMNI to 32768
- */
- ipcp->seq = msg_seq++;
+ id = ipc_addid(&msg_ids, &msq->q_perm, msg_ctlmni);
+ if(id == -1) {
+ kfree(msq);
+ return -ENOSPC;
+ }
+ msq->q_perm.mode = (msgflg & S_IRWXUGO);
+ msq->q_perm.key = key;
msq->q_stime = msq->q_rtime = 0;
msq->q_ctime = CURRENT_TIME;
msq->q_cbytes = msq->q_qnum = 0;
- msq->q_qbytes = MSGMNB;
+ msq->q_qbytes = msg_ctlmnb;
msq->q_lspid = msq->q_lrpid = 0;
INIT_LIST_HEAD(&msq->q_messages);
INIT_LIST_HEAD(&msq->q_receivers);
- init_waitqueue_head(&msq->q_rwait);
+ INIT_LIST_HEAD(&msq->q_senders);
+ msg_unlock(id);
- if (id > msg_max_id)
- msg_max_id = id;
- spin_lock(&msg_que[id].lock);
- msg_que[id].q = msq;
- spin_unlock(&msg_que[id].lock);
- msg_used_queues++;
+ return msg_buildid(id,msq->q_perm.seq);
+}
- return (int)msq->q_perm.seq * MSGMNI + id;
+static void free_msg(struct msg_msg* msg)
+{
+ struct msg_msgseg* seg;
+ seg = msg->next;
+ kfree(msg);
+ while(seg != NULL) {
+ struct msg_msgseg* tmp = seg->next;
+ kfree(seg);
+ seg = tmp;
+ }
+}
+
+static struct msg_msg* load_msg(void* src, int len)
+{
+ struct msg_msg* msg;
+ struct msg_msgseg** pseg;
+ int err;
+ int alen;
+
+ alen = len;
+ if(alen > DATALEN_MSG)
+ alen = DATALEN_MSG;
+
+ msg = (struct msg_msg *) kmalloc (sizeof(*msg) + alen, GFP_KERNEL);
+ if(msg==NULL)
+ return ERR_PTR(-ENOMEM);
+
+ msg->next = NULL;
+
+ if (copy_from_user(msg+1, src, alen)) {
+ err = -EFAULT;
+ goto out_err;
+ }
+
+ len -= alen;
+ src = ((char*)src)+alen;
+ pseg = &msg->next;
+ while(len > 0) {
+ struct msg_msgseg* seg;
+ alen = len;
+ if(alen > DATALEN_SEG)
+ alen = DATALEN_SEG;
+ seg = (struct msg_msgseg *) kmalloc (sizeof(*seg) + alen, GFP_KERNEL);
+ if(seg==NULL) {
+ err=-ENOMEM;
+ goto out_err;
+ }
+ *pseg = seg;
+ seg->next = NULL;
+ if(copy_from_user (seg+1, src, alen)) {
+ err = -EFAULT;
+ goto out_err;
+ }
+ pseg = &seg->next;
+ len -= alen;
+ src = ((char*)src)+alen;
+ }
+ return msg;
+
+out_err:
+ free_msg(msg);
+ return ERR_PTR(err);
+}
+
+static int store_msg(void* dest, struct msg_msg* msg, int len)
+{
+ int alen;
+ struct msg_msgseg *seg;
+
+ alen = len;
+ if(alen > DATALEN_MSG)
+ alen = DATALEN_MSG;
+ if(copy_to_user (dest, msg+1, alen))
+ return -1;
+
+ len -= alen;
+ dest = ((char*)dest)+alen;
+ seg = msg->next;
+ while(len > 0) {
+ alen = len;
+ if(alen > DATALEN_SEG)
+ alen = DATALEN_SEG;
+ if(copy_to_user (dest, seg+1, alen))
+ return -1;
+ len -= alen;
+ dest = ((char*)dest)+alen;
+ seg=seg->next;
+ }
+ return 0;
+}
+
+static inline void ss_add(struct msg_queue* msq, struct msg_sender* mss)
+{
+ mss->tsk=current;
+ current->state=TASK_INTERRUPTIBLE;
+ list_add_tail(&mss->list,&msq->q_senders);
+}
+
+static inline void ss_del(struct msg_sender* mss)
+{
+ if(mss->list.next != NULL)
+ list_del(&mss->list);
+}
+
+static void ss_wakeup(struct list_head* h, int kill)
+{
+ struct list_head *tmp;
+
+ tmp = h->next;
+ while (tmp != h) {
+ struct msg_sender* mss;
+
+ mss = list_entry(tmp,struct msg_sender,list);
+ tmp = tmp->next;
+ if(kill)
+ mss->list.next=NULL;
+ wake_up_process(mss->tsk);
+ }
}
static void expunge_all(struct msg_queue* msq, int res)
struct msg_queue *msq;
struct list_head *tmp;
- msq=msg_que[id].q;
- msg_que[id].q = NULL;
- if (id == msg_max_id) {
- while ((msg_que[msg_max_id].q == NULL)) {
- if(msg_max_id--== 0)
- break;
- }
- }
- msg_used_queues--;
+ msq = msg_rmid(id);
expunge_all(msq,-EIDRM);
-
- while(waitqueue_active(&msq->q_rwait)) {
- wake_up(&msq->q_rwait);
- spin_unlock(&msg_que[id].lock);
- current->policy |= SCHED_YIELD;
- schedule();
- spin_lock(&msg_que[id].lock);
- }
- spin_unlock(&msg_que[id].lock);
+ ss_wakeup(&msq->q_senders,1);
+ msg_unlock(id);
tmp = msq->q_messages.next;
while(tmp != &msq->q_messages) {
struct msg_msg* msg = list_entry(tmp,struct msg_msg,m_list);
tmp = tmp->next;
atomic_dec(&msg_hdrs);
- kfree(msg);
+ free_msg(msg);
}
atomic_sub(msq->q_cbytes, &msg_bytes);
kfree(msq);
}
-
asmlinkage long sys_msgget (key_t key, int msgflg)
{
int id, ret = -EPERM;
struct msg_queue *msq;
- down(&msg_lock);
+ down(&msg_ids.sem);
if (key == IPC_PRIVATE)
ret = newque(key, msgflg);
- else if ((id = findkey (key)) == -1) { /* key not used */
+ else if ((id = ipc_findkey(&msg_ids, key)) == -1) { /* key not used */
if (!(msgflg & IPC_CREAT))
ret = -ENOENT;
else
} else if (msgflg & IPC_CREAT && msgflg & IPC_EXCL) {
ret = -EEXIST;
} else {
- msq = msg_que[id].q;
+ msq = msg_lock(id);
+ if(msq==NULL)
+ BUG();
if (ipcperms(&msq->q_perm, msgflg))
ret = -EACCES;
else
- ret = (unsigned int) msq->q_perm.seq * MSGMNI + id;
+ ret = msg_buildid(id, msq->q_perm.seq);
+ msg_unlock(id);
}
- up(&msg_lock);
+ up(&msg_ids.sem);
return ret;
}
asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
{
- int id, err;
+ int err;
struct msg_queue *msq;
struct msqid_ds tbuf;
struct ipc_perm *ipcp;
if (msqid < 0 || cmd < 0)
return -EINVAL;
- id = msqid % MSGMNI;
+
switch (cmd) {
case IPC_INFO:
case MSG_INFO:
{
struct msginfo msginfo;
+ int max_id;
if (!buf)
return -EFAULT;
/* We must not return kernel stack data.
- * due to variable alignment, it's not enough
+ * due to padding, it's not enough
* to set all member fields.
*/
memset(&msginfo,0,sizeof(msginfo));
- msginfo.msgmni = MSGMNI;
- msginfo.msgmax = MSGMAX;
- msginfo.msgmnb = MSGMNB;
- msginfo.msgmap = MSGMAP;
- msginfo.msgpool = MSGPOOL;
- msginfo.msgtql = MSGTQL;
+ msginfo.msgmni = msg_ctlmni;
+ msginfo.msgmax = msg_ctlmax;
+ msginfo.msgmnb = msg_ctlmnb;
msginfo.msgssz = MSGSSZ;
msginfo.msgseg = MSGSEG;
+ down(&msg_ids.sem);
if (cmd == MSG_INFO) {
- msginfo.msgpool = msg_used_queues;
+ msginfo.msgpool = msg_ids.in_use;
msginfo.msgmap = atomic_read(&msg_hdrs);
msginfo.msgtql = atomic_read(&msg_bytes);
+ } else {
+ msginfo.msgmap = MSGMAP;
+ msginfo.msgpool = MSGPOOL;
+ msginfo.msgtql = MSGTQL;
}
-
+ max_id = msg_ids.max_id;
+ up(&msg_ids.sem);
if (copy_to_user (buf, &msginfo, sizeof(struct msginfo)))
return -EFAULT;
- return (msg_max_id < 0) ? 0: msg_max_id;
+ return (max_id < 0) ? 0: max_id;
}
case MSG_STAT:
case IPC_STAT:
int success_return;
if (!buf)
return -EFAULT;
- if(cmd == MSG_STAT && msqid > MSGMNI)
+ if(cmd == MSG_STAT && msqid > msg_ids.size)
return -EINVAL;
- spin_lock(&msg_que[id].lock);
- msq = msg_que[id].q;
- err = -EINVAL;
+ msq = msg_lock(msqid);
if (msq == NULL)
- goto out_unlock;
+ return -EINVAL;
+
if(cmd == MSG_STAT) {
- success_return = (unsigned int) msq->q_perm.seq * MSGMNI + msqid;
+ success_return = msg_buildid(msqid, msq->q_perm.seq);
} else {
err = -EIDRM;
- if (msq->q_perm.seq != (unsigned int) msqid / MSGMNI)
+ if (msg_checkid(msq,msqid))
goto out_unlock;
success_return = 0;
}
tbuf.msg_lspid = msq->q_lspid;
tbuf.msg_lrpid = msq->q_lrpid;
- spin_unlock(&msg_que[id].lock);
+ msg_unlock(msqid);
if (copy_to_user (buf, &tbuf, sizeof(*buf)))
return -EFAULT;
return success_return;
return -EINVAL;
}
- down(&msg_lock);
- spin_lock(&msg_que[id].lock);
- msq = msg_que[id].q;
- err = -EINVAL;
+ down(&msg_ids.sem);
+ msq = msg_lock(msqid);
+ err=-EINVAL;
if (msq == NULL)
- goto out_unlock_up;
+ goto out_up;
+
err = -EIDRM;
- if (msq->q_perm.seq != (unsigned int) msqid / MSGMNI)
+ if (msg_checkid(msq,msqid))
goto out_unlock_up;
ipcp = &msq->q_perm;
+ err = -EPERM;
+ if (current->euid != ipcp->cuid &&
+ current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN))
+ /* We _could_ check for CAP_CHOWN above, but we don't */
+ goto out_unlock_up;
switch (cmd) {
case IPC_SET:
{
int newqbytes;
- err = -EPERM;
- if (current->euid != ipcp->cuid &&
- current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN))
- /* We _could_ check for CAP_CHOWN above, but we don't */
- goto out_unlock_up;
-
if(tbuf.msg_qbytes == 0)
newqbytes = tbuf.msg_lqbytes;
else
newqbytes = tbuf.msg_qbytes;
- if (newqbytes > MSGMNB && !capable(CAP_SYS_RESOURCE))
+ if (newqbytes > msg_ctlmnb && !capable(CAP_SYS_RESOURCE))
goto out_unlock_up;
msq->q_qbytes = newqbytes;
/* sleeping senders might be able to send
* due to a larger queue size.
*/
- wake_up(&msq->q_rwait);
- spin_unlock(&msg_que[id].lock);
+ ss_wakeup(&msq->q_senders,0);
+ msg_unlock(msqid);
break;
}
case IPC_RMID:
- err = -EPERM;
- if (current->euid != ipcp->cuid &&
- current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN))
- goto out_unlock;
- freeque (id);
+ freeque (msqid);
break;
}
err = 0;
out_up:
- up(&msg_lock);
+ up(&msg_ids.sem);
return err;
out_unlock_up:
- spin_unlock(&msg_que[id].lock);
+ msg_unlock(msqid);
goto out_up;
out_unlock:
- spin_unlock(&msg_que[id].lock);
+ msg_unlock(msqid);
return err;
}
asmlinkage long sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
{
- int id;
struct msg_queue *msq;
struct msg_msg *msg;
long mtype;
int err;
- if (msgsz > MSGMAX || (long) msgsz < 0 || msqid < 0)
+ if (msgsz > msg_ctlmax || (long) msgsz < 0 || msqid < 0)
return -EINVAL;
if (get_user(mtype, &msgp->mtype))
return -EFAULT;
if (mtype < 1)
return -EINVAL;
- msg = (struct msg_msg *) kmalloc (sizeof(*msg) + msgsz, GFP_KERNEL);
- if(msg==NULL)
- return -ENOMEM;
+ msg = load_msg(msgp->mtext, msgsz);
+ if(IS_ERR(msg))
+ return PTR_ERR(msg);
- if (copy_from_user(msg+1, msgp->mtext, msgsz)) {
- kfree(msg);
- return -EFAULT;
- }
msg->m_type = mtype;
msg->m_ts = msgsz;
- id = (unsigned int) msqid % MSGMNI;
- spin_lock(&msg_que[id].lock);
- err= -EINVAL;
-retry:
- msq = msg_que[id].q;
- if (msq == NULL)
+ msq = msg_lock(msqid);
+ err=-EINVAL;
+ if(msq==NULL)
goto out_free;
-
+retry:
err= -EIDRM;
- if (msq->q_perm.seq != (unsigned int) msqid / MSGMNI)
- goto out_free;
+ if (msg_checkid(msq,msqid))
+ goto out_unlock_free;
err=-EACCES;
if (ipcperms(&msq->q_perm, S_IWUGO))
- goto out_free;
+ goto out_unlock_free;
- if(msgsz + msq->q_cbytes > msq->q_qbytes) {
- DECLARE_WAITQUEUE(wait,current);
+ if(msgsz + msq->q_cbytes > msq->q_qbytes ||
+ 1 + msq->q_qnum > msq->q_qbytes) {
+ struct msg_sender s;
if(msgflg&IPC_NOWAIT) {
err=-EAGAIN;
- goto out_free;
+ goto out_unlock_free;
}
- current->state = TASK_INTERRUPTIBLE;
- add_wait_queue(&msq->q_rwait,&wait);
- spin_unlock(&msg_que[id].lock);
+ ss_add(msq, &s);
+ msg_unlock(msqid);
schedule();
current->state= TASK_RUNNING;
+
+ msq = msg_lock(msqid);
+ err = -EIDRM;
+ if(msq==NULL)
+ goto out_free;
+ ss_del(&s);
- remove_wait_queue(&msq->q_rwait,&wait);
if (signal_pending(current)) {
- kfree(msg);
- return -EINTR;
+ err=-EINTR;
+ goto out_unlock_free;
}
-
- spin_lock(&msg_que[id].lock);
- err = -EIDRM;
goto retry;
}
msq->q_lspid = current->pid;
msq->q_stime = CURRENT_TIME;
+out_unlock_free:
+ msg_unlock(msqid);
out_free:
if(msg!=NULL)
- kfree(msg);
- spin_unlock(&msg_que[id].lock);
+ free_msg(msg);
return err;
}
struct msg_receiver msr_d;
struct list_head* tmp;
struct msg_msg* msg, *found_msg;
- int id;
int err;
int mode;
return -EINVAL;
mode = convert_mode(&msgtyp,msgflg);
- id = (unsigned int) msqid % MSGMNI;
- spin_lock(&msg_que[id].lock);
+ msq = msg_lock(msqid);
+ if(msq==NULL)
+ return -EINVAL;
retry:
- msq = msg_que[id].q;
- err=-EINVAL;
- if (msq == NULL)
- goto out_unlock;
err=-EACCES;
if (ipcperms (&msq->q_perm, S_IRUGO))
goto out_unlock;
msq->q_cbytes -= msg->m_ts;
atomic_sub(msg->m_ts,&msg_bytes);
atomic_dec(&msg_hdrs);
- if(waitqueue_active(&msq->q_rwait))
- wake_up(&msq->q_rwait);
-out_success_unlock:
- spin_unlock(&msg_que[id].lock);
+ ss_wakeup(&msq->q_senders,0);
+ msg_unlock(msqid);
out_success:
msgsz = (msgsz > msg->m_ts) ? msg->m_ts : msgsz;
if (put_user (msg->m_type, &msgp->mtype) ||
- copy_to_user (msgp->mtext, msg+1, msgsz))
- {
+ store_msg(msgp->mtext, msg, msgsz)) {
msgsz = -EFAULT;
}
- kfree(msg);
+ free_msg(msg);
return msgsz;
} else
{
+ struct msg_queue *t;
/* no message waiting. Prepare for pipelined
* receive.
*/
msr_d.r_msgtype = msgtyp;
msr_d.r_mode = mode;
if(msgflg & MSG_NOERROR)
- msr_d.r_maxsize = MSGMAX;
+ msr_d.r_maxsize = INT_MAX;
else
msr_d.r_maxsize = msgsz;
msr_d.r_msg = ERR_PTR(-EAGAIN);
current->state = TASK_INTERRUPTIBLE;
- spin_unlock(&msg_que[id].lock);
+ msg_unlock(msqid);
+
schedule();
current->state = TASK_RUNNING;
if(!IS_ERR(msg))
goto out_success;
- spin_lock(&msg_que[id].lock);
+ t = msg_lock(msqid);
+ if(t==NULL)
+ msqid=-1;
msg = (struct msg_msg*)msr_d.r_msg;
if(!IS_ERR(msg)) {
/* our message arived while we waited for
* the spinlock. Process it.
*/
- goto out_success_unlock;
+ if(msqid!=-1)
+ msg_unlock(msqid);
+ goto out_success;
}
err = PTR_ERR(msg);
if(err == -EAGAIN) {
+ if(msqid==-1)
+ BUG();
list_del(&msr_d.r_list);
if (signal_pending(current))
err=-EINTR;
}
}
out_unlock:
- spin_unlock(&msg_que[id].lock);
+ if(msqid!=-1)
+ msg_unlock(msqid);
return err;
}
off_t begin = 0;
int i, len = 0;
- down(&msg_lock);
+ down(&msg_ids.sem);
len += sprintf(buffer, " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n");
- for(i = 0; i <= msg_max_id; i++) {
- spin_lock(&msg_que[i].lock);
- if(msg_que[i].q != NULL) {
+ for(i = 0; i <= msg_ids.max_id; i++) {
+ struct msg_queue * msq;
+ msq = msg_lock(i);
+ if(msq != NULL) {
len += sprintf(buffer + len, "%10d %10d %4o %5u %5u %5u %5u %5u %5u %5u %5u %10lu %10lu %10lu\n",
- msg_que[i].q->q_perm.key,
- msg_que[i].q->q_perm.seq * MSGMNI + i,
- msg_que[i].q->q_perm.mode,
- msg_que[i].q->q_cbytes,
- msg_que[i].q->q_qnum,
- msg_que[i].q->q_lspid,
- msg_que[i].q->q_lrpid,
- msg_que[i].q->q_perm.uid,
- msg_que[i].q->q_perm.gid,
- msg_que[i].q->q_perm.cuid,
- msg_que[i].q->q_perm.cgid,
- msg_que[i].q->q_stime,
- msg_que[i].q->q_rtime,
- msg_que[i].q->q_ctime);
- spin_unlock(&msg_que[i].lock);
+ msq->q_perm.key,
+ msg_buildid(i,msq->q_perm.seq),
+ msq->q_perm.mode,
+ msq->q_cbytes,
+ msq->q_qnum,
+ msq->q_lspid,
+ msq->q_lrpid,
+ msq->q_perm.uid,
+ msq->q_perm.gid,
+ msq->q_perm.cuid,
+ msq->q_perm.cgid,
+ msq->q_stime,
+ msq->q_rtime,
+ msq->q_ctime);
+ msg_unlock(i);
pos += len;
if(pos < offset) {
}
if(pos > offset + length)
goto done;
- } else {
- spin_unlock(&msg_que[i].lock);
}
+
}
*eof = 1;
done:
- up(&msg_lock);
+ up(&msg_ids.sem);
*start = buffer + (offset - begin);
len -= (offset - begin);
if(len > length)
return len;
}
#endif
-
*
* /proc/sysvipc/sem support (c) 1999 Dragos Acostachioaie <dragos@iname.com>
*
- * SMP-threaded (c) 1999 Manfred Spraul <manfreds@colorfullife.com>
+ * SMP-threaded, sysctl's added
+ * (c) 1999 Manfred Spraul <manfreds@colorfullife.com>
*/
#include <linux/config.h>
#include <linux/spinlock.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
-
#include <asm/uaccess.h>
+#include "util.h"
+
+
+#define sem_lock(id) ((struct semid_ds*)ipc_lock(&sem_ids,id))
+#define sem_unlock(id) ipc_unlock(&sem_ids,id)
+#define sem_rmid(id) ((struct semid_ds*)ipc_rmid(&sem_ids,id))
+#define sem_checkid(sma, semid) \
+ ipc_checkid(&sem_ids,&sma->sem_perm,semid)
+#define sem_buildid(id, seq) \
+ ipc_buildid(&sem_ids, id, seq)
+static struct ipc_ids sem_ids;
-extern int ipcperms (struct ipc_perm *ipcp, short semflg);
static int newary (key_t, int, int);
-static int findkey (key_t key);
static void freeary (int id);
#ifdef CONFIG_PROC_FS
static int sysvipc_sem_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
#endif
-struct semid_ary
-{
- spinlock_t lock;
- struct semid_ds* s;
-};
-
-static struct semid_ary semary[SEMMNI];
-
-static DECLARE_MUTEX(sem_lock);
-static int max_semid = 0;
-static int used_sems = 0;
-static int used_semids = 0;
+#define SEMMSL_FAST 256 /* 512 bytes on stack */
+#define SEMOPM_FAST 64 /* ~ 372 bytes on stack */
-static unsigned short sem_seq = 0;
-
-/* anti-deadlock ordering:
- * sem_lock < semary[].lock
+/*
* linked list protection:
* sem_undo.id_next,
* semid_ds.sem_pending{,last},
- * semid_ds.sem_undo: semary[].lock for read/write
+ * semid_ds.sem_undo: sem_lock() for read/write
* sem_undo.proc_next: only "current" is allowed to read/write that field.
*
*/
+int sem_ctls[4] = {SEMMSL, SEMMNS, SEMOPM, SEMMNI};
+#define sc_semmsl (sem_ctls[0])
+#define sc_semmns (sem_ctls[1])
+#define sc_semopm (sem_ctls[2])
+#define sc_semmni (sem_ctls[3])
+
+static int used_sems = 0;
+
void __init sem_init (void)
{
- int i;
+ used_sems = 0;
+ ipc_init_ids(&sem_ids,sc_semmni);
- used_sems = used_semids = max_semid = sem_seq = 0;
- for (i = 0; i < SEMMNI; i++) {
- semary[i].lock = SPIN_LOCK_UNLOCKED;
- semary[i].s = NULL;
- }
#ifdef CONFIG_PROC_FS
create_proc_read_entry("sysvipc/sem", 0, 0, sysvipc_sem_read_proc, NULL);
#endif
- return;
-}
-
-static int findkey (key_t key)
-{
- int id;
- struct semid_ds *sma;
-
- for (id = 0; id <= max_semid; id++) {
- sma = semary[id].s;
- if(sma==NULL)
- continue;
-
- if (key == sma->sem_perm.key)
- return id;
- }
- return -1;
}
static int newary (key_t key, int nsems, int semflg)
{
int id;
struct semid_ds *sma;
- struct ipc_perm *ipcp;
int size;
if (!nsems)
return -EINVAL;
- if (used_sems + nsems > SEMMNS)
+ if (used_sems + nsems > sc_semmns)
return -ENOSPC;
- for (id = 0; id < SEMMNI; id++) {
- if(semary[id].s == NULL)
- goto found;
- }
- return -ENOSPC;
-found:
+
size = sizeof (*sma) + nsems * sizeof (struct sem);
- used_sems += nsems;
- sma = (struct semid_ds *) kmalloc (size, GFP_KERNEL);
+ sma = (struct semid_ds *) ipc_alloc(size);
if (!sma) {
- used_sems -= nsems;
return -ENOMEM;
}
memset (sma, 0, size);
+ id = ipc_addid(&sem_ids, &sma->sem_perm, sc_semmni);
+ if(id == -1) {
+ ipc_free(sma, size);
+ return -ENOSPC;
+ }
+ used_sems += nsems;
+
+ sma->sem_perm.mode = (semflg & S_IRWXUGO);
+ sma->sem_perm.key = key;
+
sma->sem_base = (struct sem *) &sma[1];
- ipcp = &sma->sem_perm;
- ipcp->mode = (semflg & S_IRWXUGO);
- ipcp->key = key;
- ipcp->cuid = ipcp->uid = current->euid;
- ipcp->gid = ipcp->cgid = current->egid;
- /* sma->sem_perm.seq*MSGMNI must be a positive integer.
- * this limits MSGMNI to 32768
- */
- sma->sem_perm.seq = sem_seq++;
/* sma->sem_pending = NULL; */
sma->sem_pending_last = &sma->sem_pending;
/* sma->undo = NULL; */
sma->sem_nsems = nsems;
sma->sem_ctime = CURRENT_TIME;
- if (id > max_semid)
- max_semid = id;
- used_semids++;
- spin_lock(&semary[id].lock);
- semary[id].s = sma;
- spin_unlock(&semary[id].lock);
- return (unsigned int) sma->sem_perm.seq * SEMMNI + id;
+ sem_unlock(id);
+
+ return sem_buildid(id, sma->sem_perm.seq);
}
asmlinkage long sys_semget (key_t key, int nsems, int semflg)
int id, err = -EINVAL;
struct semid_ds *sma;
- if (nsems < 0 || nsems > SEMMSL)
+ if (nsems < 0 || nsems > sc_semmsl)
return -EINVAL;
- down(&sem_lock);
+ down(&sem_ids.sem);
if (key == IPC_PRIVATE) {
err = newary(key, nsems, semflg);
- } else if ((id = findkey (key)) == -1) { /* key not used */
+ } else if ((id = ipc_findkey(&sem_ids, key)) == -1) { /* key not used */
if (!(semflg & IPC_CREAT))
err = -ENOENT;
else
} else if (semflg & IPC_CREAT && semflg & IPC_EXCL) {
err = -EEXIST;
} else {
- sma = semary[id].s;
+ sma = sem_lock(id);
+ if(sma==NULL)
+ BUG();
if (nsems > sma->sem_nsems)
err = -EINVAL;
else if (ipcperms(&sma->sem_perm, semflg))
err = -EACCES;
else
- err = (int) sma->sem_perm.seq * SEMMNI + id;
+ err = sem_buildid(id, sma->sem_perm.seq);
+ sem_unlock(id);
}
- up(&sem_lock);
+ up(&sem_ids.sem);
return err;
}
+/* doesn't acquire the sem_lock on error! */
+static int sem_revalidate(int semid, struct semid_ds* sma, int nsems, short flg)
+{
+ struct semid_ds* smanew;
+
+ smanew = sem_lock(semid);
+ if(smanew==NULL)
+ return -EIDRM;
+ if(smanew != sma)
+ goto out_EIDRM;
+ if(sem_checkid(sma,semid))
+ goto out_EIDRM;
+ if(sma->sem_nsems != nsems) {
+out_EIDRM:
+ sem_unlock(semid);
+ return -EIDRM;
+ }
+
+ if (ipcperms(&sma->sem_perm, flg)) {
+ sem_unlock(semid);
+ return -EACCES;
+ }
+ return 0;
+}
/* Manage the doubly linked list sma->sem_pending as a FIFO:
* insert new queue elements at the tail sma->sem_pending_last.
*/
struct semid_ds *sma;
struct sem_undo *un;
struct sem_queue *q;
+ int size;
- /* we own both locks, noone can get in */
- sma = semary[id].s;
- semary[id].s = NULL;
-
- used_sems -= sma->sem_nsems;
- if (id == max_semid)
- while (max_semid && (semary[--max_semid].s == NULL));
- used_semids--;
+ sma = sem_rmid(id);
/* Invalidate the existing undo structures for this semaphore set.
* (They will be freed without any further action in sem_exit()
q->prev = NULL;
wake_up_process(q->sleeper); /* doesn't sleep */
}
+ sem_unlock(id);
- kfree(sma);
+ used_sems -= sma->sem_nsems;
+ size = sizeof (*sma) + sma->sem_nsems * sizeof (struct sem);
+ ipc_free(sma, size);
}
int semctl_nolock(int semid, int semnum, int cmd, union semun arg)
{
int err = -EINVAL;
- int lid = semid % SEMMNI;
switch(cmd) {
case IPC_INFO:
case SEM_INFO:
{
struct seminfo seminfo;
+ int max_id;
- seminfo.semmni = SEMMNI;
- seminfo.semmns = SEMMNS;
- seminfo.semmsl = SEMMSL;
- seminfo.semopm = SEMOPM;
+ memset(&seminfo,0,sizeof(seminfo));
+ seminfo.semmni = sc_semmni;
+ seminfo.semmns = sc_semmns;
+ seminfo.semmsl = sc_semmsl;
+ seminfo.semopm = sc_semopm;
seminfo.semvmx = SEMVMX;
seminfo.semmnu = SEMMNU;
seminfo.semmap = SEMMAP;
seminfo.semume = SEMUME;
- seminfo.semusz = SEMUSZ;
- seminfo.semaem = SEMAEM;
+ down(&sem_ids.sem);
if (cmd == SEM_INFO) {
- down(&sem_lock);
- seminfo.semusz = used_semids;
+ seminfo.semusz = sem_ids.in_use;
seminfo.semaem = used_sems;
- up(&sem_lock);
+ } else {
+ seminfo.semusz = SEMUSZ;
+ seminfo.semaem = SEMAEM;
}
+ max_id = sem_ids.max_id;
+ up(&sem_ids.sem);
if (copy_to_user (arg.__buf, &seminfo, sizeof(struct seminfo)))
return -EFAULT;
- return max_semid;
+ return (max_id < 0) ? 0: max_id;
}
case SEM_STAT:
{
struct semid_ds tbuf;
int id;
- if (semid > max_semid)
+ if(semid > sem_ids.size)
+ return -EINVAL;
+
+ sma = sem_lock(semid);
+ if(sma == NULL)
return -EINVAL;
- spin_lock(&semary[lid].lock);
- err = -EINVAL;
- sma = semary[semid].s;
- if (sma == NULL)
- goto out_unlock;
err = -EACCES;
if (ipcperms (&sma->sem_perm, S_IRUGO))
goto out_unlock;
- id = (unsigned int) sma->sem_perm.seq * SEMMNI + semid;
+ id = sem_buildid(semid, sma->sem_perm.seq);
+
memset(&tbuf,0,sizeof(tbuf));
tbuf.sem_perm = sma->sem_perm;
tbuf.sem_otime = sma->sem_otime;
tbuf.sem_ctime = sma->sem_ctime;
tbuf.sem_nsems = sma->sem_nsems;
- spin_unlock(&semary[lid].lock);
+ sem_unlock(semid);
if (copy_to_user (arg.buf, &tbuf, sizeof(tbuf)))
return -EFAULT;
return id;
}
return err;
out_unlock:
- spin_unlock(&semary[lid].lock);
+ sem_unlock(semid);
return err;
}
-int semctl_locked_unlock(int semid, int semnum, int cmd, union semun arg)
+int semctl_main(int semid, int semnum, int cmd, union semun arg)
{
struct semid_ds *sma;
- struct semid_ds tbuf;
+ struct sem* curr;
int err;
- int lid = semid % SEMMNI;
+ ushort fast_sem_io[SEMMSL_FAST];
+ ushort* sem_io = fast_sem_io;
+ int nsems;
+
+ sma = sem_lock(semid);
+ if(sma==NULL)
+ return -EINVAL;
- sma = semary[lid].s;
- err=-EINVAL;
- if (sma == NULL)
- goto out_unlock;
err=-EIDRM;
- if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)
+ if (sem_checkid(sma,semid))
goto out_unlock;
err = -EACCES;
- if (ipcperms(&sma->sem_perm, S_IRUGO))
- goto out_unlock;
-
+ if (ipcperms (&sma->sem_perm, (cmd==SETVAL||cmd==SETALL)?S_IWUGO:S_IRUGO))
+ goto out_unlock;
+
+ nsems = sma->sem_nsems;
switch (cmd) {
case GETALL:
{
ushort *array = arg.array;
- ushort sem_io[SEMMSL];
int i;
- int nsems = sma->sem_nsems;
+
+ if(nsems > SEMMSL_FAST) {
+ sem_unlock(semid);
+ sem_io = ipc_alloc(sizeof(ushort)*nsems);
+ if(sem_io == NULL)
+ return -ENOMEM;
+ err = sem_revalidate(semid, sma, nsems, S_IRUGO);
+ if(err)
+ goto out_free;
+ }
for (i = 0; i < sma->sem_nsems; i++)
sem_io[i] = sma->sem_base[i].semval;
- spin_unlock(&semary[lid].lock);
- if (copy_to_user (array, sem_io, nsems*sizeof(ushort)))
- return -EFAULT;
- return 0;
+ sem_unlock(semid);
+ err = 0;
+ if(copy_to_user(array, sem_io, nsems*sizeof(ushort)))
+ err = -EFAULT;
+ goto out_free;
+ }
+ case SETALL:
+ {
+ int i;
+ struct sem_undo *un;
+
+ sem_unlock(semid);
+
+ if(nsems > SEMMSL_FAST) {
+ sem_io = ipc_alloc(sizeof(ushort)*nsems);
+ if(sem_io == NULL)
+ return -ENOMEM;
+ }
+
+ if (copy_from_user (sem_io, arg.array, nsems*sizeof(ushort))) {
+ err = -EFAULT;
+ goto out_free;
+ }
+
+ for (i = 0; i < nsems; i++) {
+ if (sem_io[i] > SEMVMX) {
+ err = -ERANGE;
+ goto out_free;
+ }
+ }
+ err = sem_revalidate(semid, sma, nsems, S_IWUGO);
+ if(err)
+ goto out_free;
+
+ for (i = 0; i < nsems; i++)
+ sma->sem_base[i].semval = sem_io[i];
+ for (un = sma->undo; un; un = un->id_next)
+ for (i = 0; i < nsems; i++)
+ un->semadj[i] = 0;
+ sma->sem_ctime = CURRENT_TIME;
+ /* maybe some queued-up processes were waiting for this */
+ update_queue(sma);
+ err = 0;
+ goto out_unlock;
}
case IPC_STAT:
+ {
+ struct semid_ds tbuf;
memset(&tbuf,0,sizeof(tbuf));
tbuf.sem_perm = sma->sem_perm;
tbuf.sem_otime = sma->sem_otime;
tbuf.sem_ctime = sma->sem_ctime;
tbuf.sem_nsems = sma->sem_nsems;
- spin_unlock(&semary[lid].lock);
+ sem_unlock(semid);
if (copy_to_user (arg.buf, &tbuf, sizeof(tbuf)))
return -EFAULT;
return 0;
-default:
- err = -EINVAL;
}
-out_unlock:
- spin_unlock(&semary[lid].lock);
- return err;
-
-}
-
-int semctl_locked(int semid, int semnum, int cmd, union semun arg)
-{
- struct semid_ds *sma;
- int lid = semid % SEMMNI;
- struct sem *curr;
-
- sma = semary[lid].s;
- if (sma == NULL)
- return -EINVAL;
-
- if (ipcperms (&sma->sem_perm, (cmd==SETVAL)?S_IWUGO:S_IRUGO))
- return -EACCES;
-
- if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)
- return -EIDRM;
-
- if (semnum >= sma->sem_nsems)
- return -EINVAL;
+ /* GETVAL, GETPID, GETNCTN, GETZCNT, SETVAL: fall-through */
+ }
+ err = -EINVAL;
+ if(semnum < 0 || semnum >= nsems)
+ goto out_unlock;
curr = &sma->sem_base[semnum];
switch (cmd) {
case GETVAL:
- return curr->semval;
+ err = curr->semval;
+ goto out_unlock;
case GETPID:
- return curr->sempid & 0xffff;
+ err = curr->sempid & 0xffff;
+ goto out_unlock;
case GETNCNT:
- return count_semncnt(sma,semnum);
+ err = count_semncnt(sma,semnum);
+ goto out_unlock;
case GETZCNT:
- return count_semzcnt(sma,semnum);
+ err = count_semzcnt(sma,semnum);
+ goto out_unlock;
case SETVAL:
{
int val = arg.val;
struct sem_undo *un;
+ err = -ERANGE;
if (val > SEMVMX || val < 0)
- return -ERANGE;
+ goto out_unlock;
for (un = sma->undo; un; un = un->id_next)
un->semadj[semnum] = 0;
sma->sem_ctime = CURRENT_TIME;
/* maybe some queued-up processes were waiting for this */
update_queue(sma);
- return 0;
+ err = 0;
+ goto out_unlock;
}
}
- return -EINVAL;
+out_unlock:
+ sem_unlock(semid);
+out_free:
+ if(sem_io != fast_sem_io)
+ ipc_free(sem_io, sizeof(ushort)*nsems);
+ return err;
}
int semctl_down(int semid, int semnum, int cmd, union semun arg)
{
struct semid_ds *sma;
int err;
- int lid = semid % SEMMNI;
struct semid_ds tbuf;
struct ipc_perm *ipcp;
if(copy_from_user (&tbuf, arg.buf, sizeof (tbuf)))
return -EFAULT;
}
- spin_lock(&semary[lid].lock);
- sma = semary[lid].s;
- err=-EINVAL;
- if (sma == NULL)
+ sma = sem_lock(semid);
+ if(sma==NULL)
+ return -EINVAL;
+
+ if (sem_checkid(sma,semid)) {
+ err=-EIDRM;
goto out_unlock;
+ }
ipcp = &sma->sem_perm;
- if(cmd == SETALL) {
- int i;
- struct sem_undo *un;
- unsigned int nsems;
- ushort sem_io[SEMMSL];
- /* SETALL doesn't belong into this
- * group, but I need the semaphore
- * for atomically reading nsems
- * and changing the semaphore values
- */
- err=-EACCES;
- if (ipcperms (ipcp, S_IWUGO))
- goto out_unlock;
- nsems=sma->sem_nsems;
- spin_unlock(&semary[lid].lock);
-
- if (copy_from_user (sem_io, arg.array, nsems*sizeof(ushort)))
- return -EFAULT;
- for (i = 0; i < nsems; i++) {
- if (sem_io[i] > SEMVMX) {
- return -ERANGE;
- }
- }
- /* we still own sem_lock, ie neither ownership
- * nor permissions of the sem array could
- * have changed. Just continue.
- */
- spin_lock(&semary[lid].lock);
- for (i = 0; i < nsems; i++)
- sma->sem_base[i].semval = sem_io[i];
- for (un = sma->undo; un; un = un->id_next)
- for (i = 0; i < nsems; i++)
- un->semadj[i] = 0;
- sma->sem_ctime = CURRENT_TIME;
- /* maybe some queued-up processes were waiting for this */
- update_queue(sma);
- err = 0;
- goto out_unlock;
- }
-
if (current->euid != ipcp->cuid &&
current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) {
err=-EPERM;
goto out_unlock;
}
-
- if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI) {
- err=-EIDRM;
- goto out_unlock;
- }
+
switch(cmd){
case IPC_RMID:
- freeary(lid);
+ freeary(semid);
err = 0;
break;
case IPC_SET:
ipcp->mode = (ipcp->mode & ~S_IRWXUGO)
| (tbuf.sem_perm.mode & S_IRWXUGO);
sma->sem_ctime = CURRENT_TIME;
+ sem_unlock(semid);
err = 0;
break;
default:
+ sem_unlock(semid);
err = -EINVAL;
+ break;
}
+ return err;
out_unlock:
- spin_unlock(&semary[lid].lock);
+ sem_unlock(semid);
return err;
}
asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg)
{
- int lid; /* lock id */
int err = -EINVAL;
- if (semid < 0 || semnum < 0 || cmd < 0)
+ if (semid < 0)
return -EINVAL;
- lid = semid % SEMMNI;
-
switch(cmd) {
case IPC_INFO:
case SEM_INFO:
err = semctl_nolock(semid,semnum,cmd,arg);
return err;
case GETALL:
- case IPC_STAT:
- spin_lock(&semary[lid].lock);
- err = semctl_locked_unlock(semid,semnum,cmd,arg);
- return err;
case GETVAL:
case GETPID:
case GETNCNT:
case GETZCNT:
+ case IPC_STAT:
case SETVAL:
- spin_lock(&semary[lid].lock);
- err= semctl_locked(semid,semnum,cmd,arg);
- spin_unlock(&semary[lid].lock);
- return err;
case SETALL:
+ err = semctl_main(semid,semnum,cmd,arg);
+ return err;
case IPC_RMID:
case IPC_SET:
- down(&sem_lock);
- err= semctl_down(semid,semnum,cmd,arg);
- up(&sem_lock);
+ down(&sem_ids.sem);
+ err = semctl_down(semid,semnum,cmd,arg);
+ up(&sem_ids.sem);
return err;
default:
return -EINVAL;
return un->proc_next;
}
+/* returns without sem_lock on error! */
static int alloc_undo(struct semid_ds *sma, struct sem_undo** unp, int semid, int alter)
{
- int size;
+ int size, nsems, error;
struct sem_undo *un;
- int error,id;
- id = (unsigned int) semid % SEMMNI;
- size = sizeof(struct sem_undo) + sizeof(short)*sma->sem_nsems;
- spin_unlock(&semary[id].lock);
+
+ nsems = sma->sem_nsems;
+ size = sizeof(struct sem_undo) + sizeof(short)*nsems;
+ sem_unlock(semid);
un = (struct sem_undo *) kmalloc(size, GFP_KERNEL);
- spin_lock(&semary[id].lock);
- if (!un) {
+ if (!un)
return -ENOMEM;
- }
- sma = semary[id].s;
- error = -EIDRM;
- if (sma == NULL)
- goto out;
- if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)
- goto out;
- if (size != sizeof(struct sem_undo) + sizeof(short)*sma->sem_nsems)
- goto out;
- error = -EACCES;
- if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO))
- goto out;
memset(un, 0, size);
+ error = sem_revalidate(semid, sma, nsems, alter ? S_IWUGO : S_IRUGO);
+ if(error) {
+ kfree(un);
+ return error;
+ }
+
un->semadj = (short *) &un[1];
un->semid = semid;
un->proc_next = current->semundo;
sma->undo = un;
*unp = un;
return 0;
-out:
- kfree(un);
- return error;
}
asmlinkage long sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
{
- int id, error = -EINVAL;
+ int error = -EINVAL;
struct semid_ds *sma;
- struct sembuf sops[SEMOPM], *sop;
+ struct sembuf fast_sops[SEMOPM_FAST];
+ struct sembuf* sops = fast_sops, *sop;
struct sem_undo *un;
int undos = 0, decrease = 0, alter = 0;
struct sem_queue queue;
if (nsops < 1 || semid < 0)
return -EINVAL;
-
- if (nsops > SEMOPM)
+ if (nsops > sc_semopm)
return -E2BIG;
- if (copy_from_user (sops, tsops, nsops * sizeof(*tsops)))
- return -EFAULT;
-
- id = (unsigned int) semid % SEMMNI;
- spin_lock(&semary[id].lock);
- sma = semary[id].s;
- error = -EINVAL;
- if (sma == NULL)
- goto out;
+ if(nsops > SEMOPM_FAST) {
+ sops = kmalloc(sizeof(*sops)*nsops,GFP_KERNEL);
+ if(sops==NULL)
+ return -ENOMEM;
+ }
+ if (copy_from_user (sops, tsops, nsops * sizeof(*tsops))) {
+ error=-EFAULT;
+ goto out_free;
+ }
+ sma = sem_lock(semid);
+ error=-EINVAL;
+ if(sma==NULL)
+ goto out_free;
error = -EIDRM;
- if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)
- goto out;
-
+ if (sem_checkid(sma,semid))
+ goto out_unlock_free;
error = -EFBIG;
for (sop = sops; sop < sops + nsops; sop++) {
if (sop->sem_num >= sma->sem_nsems)
- goto out;
+ goto out_unlock_free;
if (sop->sem_flg & SEM_UNDO)
undos++;
if (sop->sem_op < 0)
error = -EACCES;
if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO))
- goto out;
+ goto out_unlock_free;
if (undos) {
/* Make sure we have an undo structure
* for this process and this semaphore set.
}
if (!un) {
error = alloc_undo(sma,&un,semid,alter);
- if(error<0)
- goto out;
+ if(error)
+ goto out_free;
}
} else
un = NULL;
queue.undo = un;
queue.pid = current->pid;
queue.alter = decrease;
- queue.id = id;
- current->semsleeping = &queue;
+ queue.id = semid;
if (alter)
append_to_queue(sma ,&queue);
else
prepend_to_queue(sma ,&queue);
+ current->semsleeping = &queue;
for (;;) {
+ struct semid_ds* tmp;
queue.status = -EINTR;
queue.sleeper = current;
current->state = TASK_INTERRUPTIBLE;
- spin_unlock(&semary[id].lock);
+ sem_unlock(semid);
schedule();
- /* we can lock the semary even if it was
- * deleted.
- */
- spin_lock(&semary[id].lock);
+ tmp = sem_lock(semid);
+ if(tmp==NULL) {
+ if(queue.status != -EIDRM)
+ BUG();
+ current->semsleeping = NULL;
+ error = -EIDRM;
+ goto out_free;
+ }
/*
* If queue.status == 1 we where woken up and
* have to retry else we simply return.
break;
/* Everything done by update_queue */
current->semsleeping = NULL;
- goto out;
+ goto out_unlock_free;
}
}
current->semsleeping = NULL;
update:
if (alter)
update_queue (sma);
-out:
- spin_unlock(&semary[id].lock);
+out_unlock_free:
+ sem_unlock(semid);
+out_free:
+ if(sops != fast_sops)
+ kfree(sops);
return error;
}
/* If the current process was sleeping for a semaphore,
* remove it from the queue.
*/
- /* semsleeping is part of "current", and it
- * is never modified by another thread.
- * No synchronization required.
- */
if ((q = current->semsleeping)) {
- spin_lock(&semary[current->semsleeping->id].lock);
+ int semid = q->id;
+ sma = sem_lock(semid);
+ current->semsleeping = NULL;
- if (q->prev)
+ if (q->prev) {
+ if(sma==NULL)
+ BUG();
remove_from_queue(q->sma,q);
- current->semsleeping = NULL;
- spin_unlock(&semary[current->semsleeping->id].lock);
+ }
+ if(sma!=NULL)
+ sem_unlock(semid);
}
for (up = ¤t->semundo; (u = *up); *up = u->proc_next, kfree(u)) {
int semid = u->semid;
- int lid;
if(semid == -1)
continue;
- lid = semid % SEMMNI;
- spin_lock(&semary[lid].lock);
+ sma = sem_lock(semid);
+ if (sma == NULL)
+ continue;
if (u->semid == -1)
goto next_entry;
- sma = semary[lid].s;
- if (sma == NULL)
- goto next_entry;
- if (sma->sem_perm.seq != (unsigned int) u->semid / SEMMNI)
+ if (sem_checkid(sma,u->semid))
goto next_entry;
/* remove u from the sma->undo list */
/* maybe some queued-up processes were waiting for this */
update_queue(sma);
next_entry:
- spin_unlock(&semary[lid].lock);
+ sem_unlock(semid);
}
current->semundo = NULL;
}
int i, len = 0;
len += sprintf(buffer, " key semid perms nsems uid gid cuid cgid otime ctime\n");
- down(&sem_lock);
+ down(&sem_ids.sem);
- for(i = 0; i < SEMMNI; i++)
- if(semary[i].s != NULL) {
- spin_lock(&semary[i].lock);
+ for(i = 0; i <= sem_ids.max_id; i++) {
+ struct semid_ds *sma;
+ sma = sem_lock(i);
+ if(sma) {
len += sprintf(buffer + len, "%10d %10d %4o %5u %5u %5u %5u %5u %10lu %10lu\n",
- semary[i].s->sem_perm.key,
- semary[i].s->sem_perm.seq * SEMMNI + i,
- semary[i].s->sem_perm.mode,
- semary[i].s->sem_nsems,
- semary[i].s->sem_perm.uid,
- semary[i].s->sem_perm.gid,
- semary[i].s->sem_perm.cuid,
- semary[i].s->sem_perm.cgid,
- semary[i].s->sem_otime,
- semary[i].s->sem_ctime);
- spin_unlock(&semary[i].lock);
+ sma->sem_perm.key,
+ sem_buildid(i,sma->sem_perm.seq),
+ sma->sem_perm.mode,
+ sma->sem_nsems,
+ sma->sem_perm.uid,
+ sma->sem_perm.gid,
+ sma->sem_perm.cuid,
+ sma->sem_perm.cgid,
+ sma->sem_otime,
+ sma->sem_ctime);
+ sem_unlock(i);
pos += len;
if(pos < offset) {
len = 0;
- begin = pos;
+ begin = pos;
}
if(pos > offset + length)
goto done;
}
+ }
*eof = 1;
done:
- up(&sem_lock);
+ up(&sem_ids.sem);
*start = buffer + (offset - begin);
len -= (offset - begin);
if(len > length)
* get BSD style process accounting right.
* Occurs in several places in the IPC code.
* Chris Evans, <chris@ferret.lmh.ox.ac.uk>
+ * Nov 1999 - ipc helper functions, unified SMP locking
+ * Manfred Spraul <manfreds@colorfullife.com>
*/
#include <linux/config.h>
#include <linux/shm.h>
#include <linux/init.h>
#include <linux/msg.h>
-
-#include "util.h"
+#include <linux/smp_lock.h>
+#include <linux/vmalloc.h>
+#include <linux/malloc.h>
#if defined(CONFIG_SYSVIPC)
-extern void sem_init (void), msg_init (void), shm_init (void);
+#include "util.h"
void __init ipc_init (void)
{
return;
}
+void __init ipc_init_ids(struct ipc_ids* ids, int size)
+{
+ int i;
+ sema_init(&ids->sem,1);
+ ids->size = size;
+ if(size == 0)
+ return;
+ if(size > IPCMNI)
+ size = IPCMNI;
+
+ ids->in_use = 0;
+ ids->max_id = -1;
+ ids->seq = 0;
+ {
+ int seq_limit = INT_MAX/SEQ_MULTIPLIER;
+ if(seq_limit > USHRT_MAX)
+ ids->seq_max = USHRT_MAX;
+ else
+ ids->seq_max = seq_limit;
+ }
+
+ ids->entries = ipc_alloc(sizeof(struct ipc_id)*size);
+
+ if(ids->entries == NULL) {
+ printk(KERN_ERR "ipc_init_ids() failed, ipc service disabled.\n");
+ ids->size = 0;
+ }
+ ids->ary = SPIN_LOCK_UNLOCKED;
+ for(i=0;i<size;i++) {
+ ids->entries[i].p = NULL;
+ }
+}
+
+int ipc_findkey(struct ipc_ids* ids, key_t key)
+{
+ int id;
+ struct ipc_perm* p;
+
+ for (id = 0; id <= ids->max_id; id++) {
+ p = ids->entries[id].p;
+ if(p==NULL)
+ continue;
+ if (key == p->key)
+ return id;
+ }
+ return -1;
+}
+
+static int grow_ary(struct ipc_ids* ids, int newsize)
+{
+ struct ipc_id* new;
+ struct ipc_id* old;
+ int i;
+
+ if(newsize > IPCMNI)
+ newsize = IPCMNI;
+ if(newsize <= ids->size)
+ return newsize;
+
+ new = ipc_alloc(sizeof(struct ipc_id)*newsize);
+ if(new == NULL)
+ return ids->size;
+ memcpy(new, ids->entries, sizeof(struct ipc_id)*ids->size);
+ for(i=ids->size;i<newsize;i++) {
+ new[i].p = NULL;
+ }
+ spin_lock(&ids->ary);
+
+ old = ids->entries;
+ ids->entries = new;
+ i = ids->size;
+ ids->size = newsize;
+ spin_unlock(&ids->ary);
+ ipc_free(old, sizeof(struct ipc_id)*i);
+ return ids->size;
+}
+
+int ipc_addid(struct ipc_ids* ids, struct ipc_perm* new, int size)
+{
+ int id;
+
+ size = grow_ary(ids,size);
+ for (id = 0; id < size; id++) {
+ if(ids->entries[id].p == NULL)
+ goto found;
+ }
+ return -1;
+found:
+ ids->in_use++;
+ if (id > ids->max_id)
+ ids->max_id = id;
+
+ new->cuid = new->uid = current->euid;
+ new->gid = new->cgid = current->egid;
+
+ new->seq = ids->seq++;
+ if(ids->seq > ids->seq_max)
+ ids->seq = 0;
+
+ ipc_lock(ids,id);
+ ids->entries[id].p = new;
+ return id;
+}
+
+struct ipc_perm* ipc_rmid(struct ipc_ids* ids, int id)
+{
+ struct ipc_perm* p;
+ int lid = id % SEQ_MULTIPLIER;
+ if(lid > ids->size)
+ BUG();
+ p = ids->entries[lid].p;
+ ids->entries[lid].p = NULL;
+ if(p==NULL)
+ BUG();
+ ids->in_use--;
+
+ if (lid == ids->max_id) {
+ do {
+ lid--;
+ if(lid == -1)
+ break;
+ } while (ids->entries[lid].p == NULL);
+ ids->max_id = lid;
+ }
+ return p;
+}
+
+void* ipc_alloc(int size)
+{
+ void* out;
+ if(size > PAGE_SIZE) {
+ lock_kernel();
+ out = vmalloc(size);
+ unlock_kernel();
+ } else {
+ out = kmalloc(size, GFP_KERNEL);
+ }
+ return out;
+}
+
+void ipc_free(void* ptr, int size)
+{
+ if(size > PAGE_SIZE) {
+ lock_kernel();
+ vfree(ptr);
+ unlock_kernel();
+ } else {
+ kfree(ptr);
+ }
+}
+
/*
* Check user, group, other permissions for access
* to ipc resources. return 0 if allowed
/*
* linux/ipc/util.h
* Copyright (C) 1999 Christoph Rohland
+ *
+ * ipc helper functions (c) 1999 Manfred Spraul <manfreds@colorfullife.com>
*/
-/*
- * IPCMNI is the absolute maximum for ipc identifier. This is used to
- * detect stale identifiers
+#define USHRT_MAX 0xffff
+#define SEQ_MULTIPLIER (IPCMNI)
+
+void sem_init (void);
+void msg_init (void);
+void shm_init (void);
+
+struct ipc_ids {
+ int size;
+ int in_use;
+ int max_id;
+ unsigned short seq;
+ unsigned short seq_max;
+ struct semaphore sem;
+ spinlock_t ary;
+ struct ipc_id* entries;
+};
+
+struct ipc_id {
+ struct ipc_perm* p;
+};
+
+
+void __init ipc_init_ids(struct ipc_ids* ids, int size);
+
+/* must be called with ids->sem acquired.*/
+int ipc_findkey(struct ipc_ids* ids, key_t key);
+int ipc_addid(struct ipc_ids* ids, struct ipc_perm* new, int size);
+
+/* must be called with both locks acquired. */
+struct ipc_perm* ipc_rmid(struct ipc_ids* ids, int id);
+
+int ipcperms (struct ipc_perm *ipcp, short flg);
+
+/* for rare, potentially huge allocations.
+ * both function can sleep
*/
-#define IPCMNI (1<<15)
+void* ipc_alloc(int size);
+void ipc_free(void* ptr, int size);
+
+extern inline struct ipc_perm* ipc_lock(struct ipc_ids* ids, int id)
+{
+ struct ipc_perm* out;
+ int lid = id % SEQ_MULTIPLIER;
+ if(lid > ids->size)
+ return NULL;
+
+ spin_lock(&ids->ary);
+ out = ids->entries[lid].p;
+ if(out==NULL)
+ spin_unlock(&ids->ary);
+ return out;
+}
+
+extern inline void ipc_unlock(struct ipc_ids* ids, int id)
+{
+ spin_unlock(&ids->ary);
+}
+
+extern inline int ipc_buildid(struct ipc_ids* ids, int id, int seq)
+{
+ return SEQ_MULTIPLIER*seq + id;
+}
+
+extern inline int ipc_checkid(struct ipc_ids* ids, struct ipc_perm* ipcp, int uid)
+{
+ if(uid/SEQ_MULTIPLIER != ipcp->seq)
+ return 1;
+ return 0;
+}
-extern int ipcperms (struct ipc_perm *ipcp, short shmflg);
struct module * m;
if (module_list == &kernel_module)
- return ((size_t)high_memory - PAGE_OFFSET + PAGE_SIZE);
+ return ((unsigned long)high_memory - PAGE_OFFSET + PAGE_SIZE);
/* shouldn't we have a rw spinlock for module_list? */
lock_kernel();
/* no MODULES so high_memory is good enough for /proc/kcore (TA) */
unsigned long get_kcore_size(void)
{
- return ((size_t)high_memory - PAGE_OFFSET + PAGE_SIZE);
+ return ((unsigned long)high_memory - PAGE_OFFSET + PAGE_SIZE);
}
static rwlock_t resource_lock = RW_LOCK_UNLOCKED;
/*
- * This generates reports for /proc/ioports and /proc/memory
+ * This generates reports for /proc/ioports and /proc/iomem
*/
static char * do_resource_list(struct resource *entry, const char *fmt, int offset, char *buf, char *end)
{
#endif
#ifdef CONFIG_SYSVIPC
extern size_t shm_prm[];
+extern int msg_ctlmax;
+extern int msg_ctlmnb;
+extern int msg_ctlmni;
+extern int sem_ctls[];
#endif
#ifdef __sparc__
#ifdef CONFIG_SYSVIPC
{KERN_SHMMAX, "shmmax", &shm_prm, 3*sizeof (size_t),
0644, NULL, &proc_doulongvec_minmax},
+ {KERN_MSGMAX, "msgmax", &msg_ctlmax, sizeof (int),
+ 0644, NULL, &proc_dointvec},
+ {KERN_MSGMNI, "msgmni", &msg_ctlmni, sizeof (int),
+ 0644, NULL, &proc_dointvec},
+ {KERN_MSGMNB, "msgmnb", &msg_ctlmnb, sizeof (int),
+ 0644, NULL, &proc_dointvec},
+ {KERN_SEM, "sem", &sem_ctls, 4*sizeof (int),
+ 0644, NULL, &proc_dointvec},
#endif
#ifdef CONFIG_MAGIC_SYSRQ
{KERN_SYSRQ, "sysrq", &sysrq_enabled, sizeof (int),
*
*/
+extern void net_device_init(void);
extern void ip_auto_config(void);
int __init net_dev_init(void)