Commit f4a818e0 authored by Linus Torvalds's avatar Linus Torvalds

Import 1.1.55

parent 057f54fb
VERSION = 1
PATCHLEVEL = 1
SUBLEVEL = 54
SUBLEVEL = 55
ARCH = i386
......
......@@ -25,9 +25,9 @@
/* Define the following if you don't like that your drives seek audibly
* after a disk change
* after a disk change (but it may not work correctly for everybody)
*/
#define SILENT_DC_CLEAR
/* #define SILENT_DC_CLEAR */
/* End of configuration */
......@@ -304,7 +304,7 @@ static struct floppy_struct floppy_type[32] = {
{ 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"CompaQ"}, /* 9 2.88MB 3.5" */
{ 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" }, /* 10 1.44MB 5.25" */
{ 3360,21,2,80,0,0x1C,0x00,0xCF,0x6C,"H1680" }, /* 11 1.68MB 3.5" */
{ 3360,21,2,80,0,0x1C,0x00,0xCF,0x0C,"H1680" }, /* 11 1.68MB 3.5" */
{ 820,10,2,41,1,0x25,0x01,0xDF,0x2E,"h410" }, /* 12 410KB 5.25" */
{ 1640,10,2,82,0,0x25,0x02,0xDF,0x2E,"H820" }, /* 13 820KB 3.5" */
{ 2952,18,2,82,0,0x25,0x00,0xDF,0x02,"h1476" }, /* 14 1.48MB 5.25" */
......@@ -317,8 +317,8 @@ static struct floppy_struct floppy_type[32] = {
{ 1760,11,2,80,0,0x1C,0x09,0xCF,0x6C,"h880" }, /* 20 880KB 5.25" */
{ 2080,13,2,80,0,0x1C,0x01,0xCF,0x6C,"D1040" }, /* 21 1.04MB 3.5" */
{ 2240,14,2,80,0,0x1C,0x19,0xCF,0x6C,"D1120" }, /* 22 1.12MB 3.5" */
{ 3200,20,2,80,0,0x1C,0x20,0xCF,0x6C,"h1600" }, /* 23 1.6MB 5.25" */
{ 3520,22,2,80,0,0x1C,0x08,0xCF,0x6C,"H1760" }, /* 24 1.76MB 3.5" */
{ 3200,20,2,80,0,0x1C,0x20,0xCF,0x2C,"h1600" }, /* 23 1.6MB 5.25" */
{ 3520,22,2,80,0,0x1C,0x08,0xCF,0x2e,"H1760" }, /* 24 1.76MB 3.5" */
{ 3840,24,2,80,0,0x1C,0x20,0xCF,0x6C,"H1920" }, /* 25 1.92MB 3.5" */
{ 6400,40,2,80,0,0x25,0x5B,0xCF,0x6C,"E3200" }, /* 26 3.20MB 3.5" */
{ 7040,44,2,80,0,0x25,0x5B,0xCF,0x6C,"E3520" }, /* 27 3.52MB 3.5" */
......@@ -326,7 +326,7 @@ static struct floppy_struct floppy_type[32] = {
{ 3680,23,2,80,0,0x1C,0x10,0xCF,0x6C,"H1840" }, /* 29 1.84MB 3.5" */
{ 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"D800" }, /* 30 800KB 3.5" */
{ 3200,20,2,80,0,0x1C,0x00,0xCF,0x6C,"H1600" }, /* 31 1.6MB 3.5" */
{ 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5" */
};
#define NUMBER(x) (sizeof(x) / sizeof(*(x)))
......@@ -1278,9 +1278,10 @@ static void recal_interrupt(void)
debugt("recal interrupt need 1 recal:");
#endif
/* after a second recalibrate, we still haven't
* reached track 0. Probably no drive */
DRS->track = PROVEN_ABSENT;
cont->done(0);
* reached track 0. Probably no drive. Raise an
* error, as failing immediately might upset
* computers possessed by the Devil :-) */
cont->error();
cont->redo();
return;
case NEED_2_RECAL:
......@@ -1691,7 +1692,7 @@ static void setup_format_params(void)
int count,head_shift,track_shift;
raw_cmd.flags = FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK;
/*FD_RAW_NEED_DISK |*/ FD_RAW_NEED_SEEK;
raw_cmd.rate = floppy->rate & 0x3;
raw_cmd.cmd_count = NR_F;
COMMAND = FM_MODE(floppy,FD_FORMAT);
......
......@@ -15,10 +15,8 @@
* Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
* in the early extended-partition checks and added DM partitions
*
* IDE IRQ-unmask & drive-id & multiple-mode code added by Mark Lord.
*
* Support for BIOS drive geometry translation added by Mark Lord.
* -- hd.c no longer chokes on drives with "more than 16 heads".
* IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
* and general streamlining by mlord@bnr.ca (Mark Lord).
*/
#define DEFAULT_MULT_COUNT 0 /* set to 0 to disable multiple mode at boot */
......@@ -62,6 +60,9 @@ static inline unsigned char CMOS_READ(unsigned char addr)
#define RECAL_FREQ 4 /* Recalibrate every 4th retry */
#define MAX_HD 2
#define STAT_OK (READY_STAT|SEEK_STAT)
#define OK_STATUS(s) (((s)&(STAT_OK|(BUSY_STAT|WRERR_STAT|ERR_STAT)))==STAT_OK)
static void recal_intr(void);
static void bad_rw_intr(void);
......@@ -135,12 +136,12 @@ void hd_setup(char *str, int *ints)
static void dump_status (char *msg, unsigned int stat)
{
unsigned long flags;
char dev;
char devc;
dev = CURRENT ? 'a' + DEVICE_NR(CURRENT->dev) : '?';
devc = CURRENT ? 'a' + DEVICE_NR(CURRENT->dev) : '?';
save_flags (flags);
sti();
printk("hd%c: %s: status=0x%02x { ", dev, msg, stat & 0xff);
printk("hd%c: %s: status=0x%02x { ", devc, msg, stat & 0xff);
if (stat & BUSY_STAT) printk("Busy ");
if (stat & READY_STAT) printk("DriveReady ");
if (stat & WRERR_STAT) printk("WriteFault ");
......@@ -150,55 +151,48 @@ static void dump_status (char *msg, unsigned int stat)
if (stat & INDEX_STAT) printk("Index ");
if (stat & ERR_STAT) printk("Error ");
printk("}\n");
if (stat & ERR_STAT) {
unsigned int err = inb(HD_ERROR);
printk("hd%c: %s: error=0x%02x { ", dev, msg, err & 0xff);
if (err & BBD_ERR) printk("BadSector ");
if (err & ECC_ERR) printk("UncorrectableError ");
if (err & ID_ERR) printk("SectorIdNotFound ");
if (err & ABRT_ERR) printk("DriveStatusError ");
if (err & TRK0_ERR) printk("TrackZeroNotFound ");
if (err & MARK_ERR) printk("AddrMarkNotFound ");
if ((stat & ERR_STAT) == 0) {
hd_error = 0;
} else {
hd_error = inb(HD_ERROR);
printk("hd%c: %s: error=0x%02x { ", devc, msg, hd_error & 0xff);
if (hd_error & BBD_ERR) printk("BadSector ");
if (hd_error & ECC_ERR) printk("UncorrectableError ");
if (hd_error & ID_ERR) printk("SectorIdNotFound ");
if (hd_error & ABRT_ERR) printk("DriveStatusError ");
if (hd_error & TRK0_ERR) printk("TrackZeroNotFound ");
if (hd_error & MARK_ERR) printk("AddrMarkNotFound ");
printk("}");
if (err & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) {
if (CURRENT)
printk(", sector=%ld", CURRENT->sector);
if (hd_error & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) {
printk(", CHS=%d/%d/%d", (inb(HD_HCYL)<<8) + inb(HD_LCYL),
inb(HD_CURRENT) & 0xf, inb(HD_SECTOR));
if (CURRENT)
printk(", sector=%ld", CURRENT->sector);
}
printk("\n");
}
restore_flags (flags);
}
static int win_result(void)
void check_status(void)
{
int i=inb_p(HD_STATUS);
int i = inb_p(HD_STATUS);
if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
== (READY_STAT | SEEK_STAT)) {
hd_error = 0;
return 0; /* ok */
if (!OK_STATUS(i)) {
dump_status("check_status", i);
bad_rw_intr();
}
dump_status("win_result", i);
return 1;
}
static int controller_busy(void);
static int status_ok(void);
static int controller_ready(unsigned int drive, unsigned int head)
static int controller_busy(void)
{
int retry = 100;
int retries = 100000;
unsigned char status;
do {
if (controller_busy() & BUSY_STAT)
return 0;
outb_p(0xA0 | (drive<<4) | head, HD_CURRENT);
if (status_ok())
return 1;
} while (--retry);
return 0;
status = inb_p(HD_STATUS);
} while ((status & BUSY_STAT) && --retries);
return status;
}
static int status_ok(void)
......@@ -206,7 +200,7 @@ static int status_ok(void)
unsigned char status = inb_p(HD_STATUS);
if (status & BUSY_STAT)
return 1;
return 1; /* Ancient, but does it make sense??? */
if (status & WRERR_STAT)
return 0;
if (!(status & READY_STAT))
......@@ -216,15 +210,18 @@ static int status_ok(void)
return 1;
}
static int controller_busy(void)
static int controller_ready(unsigned int drive, unsigned int head)
{
int retries = 100000;
unsigned char status;
int retry = 100;
do {
status = inb_p(HD_STATUS);
} while ((status & BUSY_STAT) && --retries);
return status;
if (controller_busy() & BUSY_STAT)
return 0;
outb_p(0xA0 | (drive<<4) | head, HD_CURRENT);
if (status_ok())
return 1;
} while (--retry);
return 0;
}
static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
......@@ -233,13 +230,6 @@ static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
{
unsigned short port;
#ifdef DEBUG
if (drive>1 || head>15) {
printk("bad drive mapping, trying to access drive=%d, cyl=%d, head=%d, sect=%d\n",
drive, cyl, head, sect);
panic("harddisk driver problem");
}
#endif
#if (HD_DELAY > 0)
while (read_timer() - last_req < HD_DELAY)
/* nothing */;
......@@ -346,7 +336,7 @@ static void identify_intr(void)
/*
* Early model Quantum drives go weird at this point,
* but doing a recalibrate seems to "fix" them.
* (Doing a full reset confuses some newer model Quantums)
* (Doing a full reset confuses some other model Quantums)
*/
if (!strncmp(id->model, "QUANTUM", 7))
special_op[dev] = recalibrate[dev] = 1;
......@@ -366,7 +356,7 @@ static void set_multmode_intr(void)
sti();
if (stat & (BUSY_STAT|ERR_STAT)) {
mult_req[dev] = mult_count[dev] = 0;
dump_status("set multiple mode failed", stat);
dump_status("set multmode failed", stat);
} else {
if ((mult_count[dev] = mult_req[dev]))
printk (" hd%c: enabled %d-sector multiple mode\n",
......@@ -388,8 +378,7 @@ static int drive_busy(void)
for (i = 0; i < 500000 ; i++) {
c = inb_p(HD_STATUS);
c &= (BUSY_STAT | READY_STAT | SEEK_STAT);
if (c == (READY_STAT | SEEK_STAT))
if ((c & (BUSY_STAT | READY_STAT | SEEK_STAT)) == STAT_OK)
return 0;
}
dump_status("reset timed out", c);
......@@ -405,9 +394,9 @@ static void reset_controller(void)
outb_p(hd_info[0].ctl & 0x0f,HD_CMD);
for(i = 0; i < 1000; i++) nop();
if (drive_busy())
printk("HD-controller still busy\n");
if ((hd_error = inb(HD_ERROR)) != 1)
printk("HD-controller reset failed: %02x\n",hd_error);
printk("hd: controller still busy\n");
else if ((hd_error = inb(HD_ERROR)) != 1)
printk("hd: controller reset failed: %02x\n",hd_error);
}
static void reset_hd(void)
......@@ -419,12 +408,13 @@ static void reset_hd(void)
reset = 0;
i = -1;
reset_controller();
} else if (win_result()) {
bad_rw_intr();
} else {
check_status();
if (reset)
goto repeat;
}
if (++i < NR_HD) {
special_op[i] = recalibrate[i] = 1;
if (unmask_intr[i]) {
unmask_intr[i] = DEFAULT_UNMASK_INTR;
printk("hd%c: reset irq-unmasking to %d\n",i+'a',
......@@ -444,7 +434,6 @@ static void reset_hd(void)
hd_request();
}
/*
* Ok, don't know what to do with the unexpected interrupts: on some machines
* doing a reset and a retry seems to result in an eternal loop. Right now I
......@@ -478,11 +467,11 @@ static void bad_rw_intr(void)
dev = DEVICE_NR(CURRENT->dev);
if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
end_request(0);
special_op[dev] += recalibrate[dev] = 1;
special_op[dev] = recalibrate[dev] = 1;
} else if (CURRENT->errors % RESET_FREQ == 0)
reset = 1;
else if ((hd_error & TRK0_ERR) || CURRENT->errors % RECAL_FREQ == 0)
special_op[dev] += recalibrate[dev] = 1;
special_op[dev] = recalibrate[dev] = 1;
/* Otherwise just retry */
}
......@@ -497,9 +486,6 @@ static inline int wait_DRQ(void)
return -1;
}
#define STAT_MASK (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT)
#define STAT_OK (READY_STAT | SEEK_STAT)
static void read_intr(void)
{
unsigned int dev = DEVICE_NR(CURRENT->dev);
......@@ -511,7 +497,7 @@ static void read_intr(void)
i = (unsigned) inb_p(HD_STATUS);
if (i & BUSY_STAT)
continue;
if ((i & STAT_MASK) != STAT_OK)
if (!OK_STATUS(i))
break;
if (i & DRQ_STAT)
goto ok_to_read;
......@@ -534,9 +520,9 @@ static void read_intr(void)
i = (CURRENT->nr_sectors -= nsect);
#ifdef DEBUG
printk("hd%c: read: sectors(%ld-%ld), remaining=%ld, buffer=%08lx\n",
printk("hd%c: read: sectors(%ld-%ld), remaining=%ld, buffer=0x%08lx\n",
dev+'a', CURRENT->sector, CURRENT->sector+nsect,
CURRENT->nr_sectors, (long) CURRENT->buffer+(nsect<<9));
CURRENT->nr_sectors, (unsigned long) CURRENT->buffer+(nsect<<9));
#endif
if ((CURRENT->current_nr_sectors -= nsect) <= 0)
end_request(1);
......@@ -581,7 +567,7 @@ static void multwrite_intr(void)
if (unmask_intr[dev])
sti();
if (((i = inb_p(HD_STATUS)) & STAT_MASK) == STAT_OK) {
if (OK_STATUS(i=inb_p(HD_STATUS))) {
if (i & DRQ_STAT) {
if (WCURRENT.nr_sectors) {
multwrite(dev);
......@@ -619,7 +605,7 @@ static void write_intr(void)
i = (unsigned) inb_p(HD_STATUS);
if (i & BUSY_STAT)
continue;
if ((i & STAT_MASK) != STAT_OK)
if (!OK_STATUS(i))
break;
if ((CURRENT->nr_sectors <= 1) || (i & DRQ_STAT))
goto ok_to_write;
......@@ -650,8 +636,7 @@ static void write_intr(void)
static void recal_intr(void)
{
if (win_result())
bad_rw_intr();
check_status();
#if (HD_DELAY > 0)
last_req = read_timer();
#endif
......@@ -664,116 +649,118 @@ static void recal_intr(void)
*/
static void hd_times_out(void)
{
unsigned int dev;
DEVICE_INTR = NULL;
sti();
if (!CURRENT)
return;
disable_irq(HD_IRQ);
sti();
reset = 1;
printk(KERN_DEBUG "HD timeout\n");
dev = DEVICE_NR(CURRENT->dev);
printk("hd%c: timeout\n", dev+'a');
if (++CURRENT->errors >= MAX_ERRORS) {
#ifdef DEBUG
printk("hd : too many errors.\n");
printk("hd%c: too many errors\n", dev+'a');
#endif
end_request(0);
}
cli();
hd_request();
enable_irq(HD_IRQ);
}
int do_special_op (unsigned int dev)
{
if (recalibrate[dev]) {
recalibrate[dev] = 0;
hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
return reset;
}
if (!identified[dev]) {
identified[dev] = 1;
unmask_intr[dev] = DEFAULT_UNMASK_INTR;
mult_req[dev] = DEFAULT_MULT_COUNT;
hd_out(dev,0,0,0,0,WIN_IDENTIFY,&identify_intr);
return reset;
}
if (mult_req[dev] != mult_count[dev]) {
hd_out(dev,mult_req[dev],0,0,0,WIN_SETMULT,&set_multmode_intr);
return reset;
}
if (hd_info[dev].head > 16) {
printk ("hd%c: cannot handle device with more than 16 heads - giving up\n", dev+'a');
end_request(0);
}
special_op[dev] = 0;
return 1;
}
/*
* The driver has been modified to enable interrupts a bit more: in order to
* do this we first (a) disable the timeout-interrupt and (b) clear the
* device-interrupt. This way the interrupts won't mess with out code (the
* worst that can happen is that an unexpected HD-interrupt comes in and
* sets the "reset" variable and starts the timer)
* The driver enables interrupts as much as possible. In order to do this,
* (a) the device-interrupt is disabled before entering hd_request(),
* and (b) the timeout-interrupt is disabled before the sti().
*
* Interrupts are still masked (by default) whenever we are exchanging
* data/cmds with a drive, because some drives seem to have very poor
* tolerance for latency during I/O. For devices which don't suffer from
* that problem (most don't), the unmask_intr[] flag can be set to unmask
* other interrupts during data/cmd transfers (by defining DEFAULT_UNMASK_INTR
* to 1, or by using "hdparm -u1 /dev/hd?" from the shell).
*/
static void hd_request(void)
{
unsigned int block,dev;
unsigned int sec,head,cyl,track;
unsigned int nsect;
unsigned int dev, block, nsect, sec, track, head, cyl;
if (CURRENT && CURRENT->dev < 0) return;
if (DEVICE_INTR)
return;
repeat:
timer_active &= ~(1<<HD_TIMER);
sti();
INIT_REQUEST;
if (reset) {
cli();
reset_hd();
return;
}
dev = MINOR(CURRENT->dev);
block = CURRENT->sector;
nsect = CURRENT->nr_sectors;
if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects) {
if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects || ((block+nsect) > hd[dev].nr_sects)) {
#ifdef DEBUG
printk("hd : attempted read for sector %d past end of device at sector %d.\n",
block, hd[dev].nr_sects);
if (dev >= (NR_HD<<6))
printk("hd: bad minor number: device=0x%04x\n", CURRENT->dev);
else
printk("hd%c: bad access: block=%d, count=%d\n",
(CURRENT->dev>>6)+'a', block, nsect);
#endif
end_request(0);
goto repeat;
}
block += hd[dev].start_sect;
dev >>= 6;
sec = block % hd_info[dev].sect + 1;
if (special_op[dev]) {
if (do_special_op(dev))
goto repeat;
return;
}
sec = block % hd_info[dev].sect + 1;
track = block / hd_info[dev].sect;
head = track % hd_info[dev].head;
cyl = track / hd_info[dev].head;
head = track % hd_info[dev].head;
cyl = track / hd_info[dev].head;
#ifdef DEBUG
printk("hd%c : cyl = %d, head = %d, sector = %d, buffer = %08x\n",
dev+'a', cyl, head, sec, CURRENT->buffer);
printk("hd%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx\n",
dev+'a', (CURRENT->cmd == READ)?"read":"writ",
cyl, head, sec, nsect, (unsigned long) CURRENT->buffer);
#endif
if (!unmask_intr[dev])
cli();
if (reset) {
int i;
for (i=0; i < NR_HD; i++)
special_op[i] = recalibrate[i] = 1;
cli(); /* better play it safe, as resets are the last resort */
reset_hd();
return;
}
if (special_op[dev]) { /* we use "special_op" to reduce overhead on r/w */
if (recalibrate[dev]) {
recalibrate[dev] = 0;
hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
if (reset)
goto repeat;
return;
}
if (!identified[dev]) {
identified[dev] = 1;
unmask_intr[dev] = DEFAULT_UNMASK_INTR;
mult_req[dev] = DEFAULT_MULT_COUNT;
hd_out(dev,0,0,0,0,WIN_IDENTIFY,&identify_intr);
if (reset)
goto repeat;
return;
}
if (mult_req[dev] != mult_count[dev]) {
hd_out(dev,mult_req[dev],0,0,0,WIN_SETMULT,&set_multmode_intr);
if (reset)
goto repeat;
return;
}
if (hd_info[dev].head > 16) {
printk ("hd%c: cannot handle device with more than 16 heads - giving up\n", dev+'a');
end_request(0);
goto repeat;
}
--special_op[dev];
} /* special_op[dev] */
if (CURRENT->cmd == READ) {
unsigned int cmd = mult_count[dev] > 1 ? WIN_MULTREAD : WIN_READ;
hd_out(dev,nsect,sec,head,cyl,cmd,&read_intr);
if (reset)
goto repeat;
#ifdef DEBUG
printk("hd%c: reading %d sectors(%ld-%ld), buffer=%08lx\n",
dev+'a', nsect, CURRENT->sector,
CURRENT->sector+nsect-1, (long) CURRENT->buffer);
#endif
return;
}
if (CURRENT->cmd == WRITE) {
......@@ -783,11 +770,6 @@ static void hd_request(void)
hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
if (reset)
goto repeat;
#ifdef DEBUG
printk("hd%c: writing %d sectors(%ld-%ld), buffer=%08lx\n",
dev+'a', nsect, CURRENT->sector,
CURRENT->sector+nsect-1, (long) CURRENT->buffer);
#endif
if (wait_DRQ()) {
bad_rw_intr();
goto repeat;
......@@ -795,9 +777,8 @@ static void hd_request(void)
if (mult_count[dev]) {
WCURRENT = *CURRENT;
multwrite(dev);
} else {
} else
outsw(HD_DATA,CURRENT->buffer,256);
}
return;
}
panic("unknown hd-command");
......@@ -905,11 +886,11 @@ static int hd_ioctl(struct inode * inode, struct file * file,
if (arg > max_mult[dev])
err = -EINVAL; /* out of range for device */
else if (mult_req[dev] != mult_count[dev]) {
++special_op[dev];
special_op[dev] = 1;
err = -EBUSY; /* busy, try again */
} else {
mult_req[dev] = arg;
++special_op[dev];
special_op[dev] = 1;
err = 0;
}
restore_flags(flags);
......@@ -1045,22 +1026,14 @@ static void hd_geninit(void)
}
i = NR_HD;
while (i-- > 0) {
hd[i<<6].nr_sects = 0;
if (bios_info[i].head > 16) {
/*
* The newer E-IDE BIOSs handle drives larger than 1024
* cylinders by increasing the number of logical heads
* to keep the number of logical cylinders below the
* sacred INT13 limit of 1024 (10 bits). If that is
* what's happening here, we'll find out and correct
* it later when "identifying" the drive.
*/
printk("hd.c: IDE/ST-506 disk with more than 16 heads detected.\n");
printk(" (hd%c: cyl=%d, sect=%d, head=%d)\n", i+'a',
bios_info[i].cyl,
bios_info[i].sect,
bios_info[i].head);
}
/*
* The newer E-IDE BIOSs handle drives larger than 1024
* cylinders by increasing the number of logical heads
* to keep the number of logical cylinders below the
* sacred INT13 limit of 1024 (10 bits). If that is
* what's happening here, we'll find out and correct
* it later when "identifying" the drive.
*/
hd[i<<6].nr_sects = bios_info[i].head *
bios_info[i].sect * bios_info[i].cyl;
hd_ident_info[i] = (struct hd_driveid *) kmalloc(512,GFP_KERNEL);
......@@ -1068,7 +1041,7 @@ static void hd_geninit(void)
}
if (NR_HD) {
if (request_irq(HD_IRQ, hd_interrupt, SA_INTERRUPT, "hd")) {
printk("hd.c: unable to get IRQ%d for the harddisk driver\n",HD_IRQ);
printk("hd: unable to get IRQ%d for the harddisk driver\n",HD_IRQ);
NR_HD = 0;
}
}
......@@ -1094,7 +1067,7 @@ static struct file_operations hd_fops = {
unsigned long hd_init(unsigned long mem_start, unsigned long mem_end)
{
if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
printk("Unable to get major %d for harddisk\n",MAJOR_NR);
printk("hd: unable to get major %d for harddisk\n",MAJOR_NR);
return mem_start;
}
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
......
......@@ -514,4 +514,12 @@ int init_module(void)
return 0;
}
void cleanup_module(void)
{
if(MOD_IN_USE)
printk("lp: busy - remove delayed\n");
else
unregister_chrdev(LP_MAJOR,"lp");
}
#endif
......@@ -54,7 +54,11 @@ config: configure /usr/include/sys/soundcard.h
@echo \#define SOUND_CONFIG_DATE \"`date`\" >> local.h
@echo \#define SOUND_CONFIG_BY \"`whoami`\" >> local.h
@echo \#define SOUND_CONFIG_HOST \"`hostname`\" >> local.h
@echo \#define SOUND_CONFIG_DOMAIN \"`domainname`\" >> local.h
@if [ -x /bin/dnsdomainname ]; then \
echo \#define SOUND_CONFIG_DOMAIN \"`dnsdomainname`\"; \
else \
echo \#define SOUND_CONFIG_DOMAIN \"`domainname`\"; \
fi >> local.h
clrconf:
rm -f local.h .depend
......
......@@ -612,8 +612,8 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
current->mm->start_code = start_code;
current->mm->end_data = end_data;
current->mm->start_stack = bprm->p;
current->suid = current->euid = bprm->e_uid;
current->sgid = current->egid = bprm->e_gid;
current->suid = current->euid = current->fsuid = bprm->e_uid;
current->sgid = current->egid = current->fsgid = bprm->e_gid;
/* Calling sys_brk effectively mmaps the pages that we need for the bss and break
sections */
......
......@@ -20,6 +20,9 @@
#include <linux/ext_fs.h>
#include <linux/stat.h>
#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
#define ROUND_UP(x) (((x)+3) & ~3)
static int ext_dir_read(struct inode * inode, struct file * filp, char * buf, int count)
{
return -EISDIR;
......@@ -65,6 +68,7 @@ static int ext_readdir(struct inode * inode, struct file * filp,
struct dirent * dirent, int count)
{
unsigned int i;
unsigned int ret;
off_t offset;
char c;
struct buffer_head * bh;
......@@ -74,15 +78,23 @@ static int ext_readdir(struct inode * inode, struct file * filp,
return -EBADF;
if ((filp->f_pos & 7) != 0)
return -EBADF;
while (filp->f_pos < inode->i_size) {
ret = 0;
while (!ret && filp->f_pos < inode->i_size) {
offset = filp->f_pos & 1023;
bh = ext_bread(inode,(filp->f_pos)>>BLOCK_SIZE_BITS,0);
if (!bh) {
filp->f_pos += 1024-offset;
continue;
}
for (i = 0; i < 1024 && i < offset; ) {
de = (struct ext_dir_entry *) (bh->b_data + i);
if (!de->rec_len)
break;
i += de->rec_len;
}
offset = i;
de = (struct ext_dir_entry *) (offset + bh->b_data);
while (offset < 1024 && filp->f_pos < inode->i_size) {
while (!ret && offset < 1024 && filp->f_pos < inode->i_size) {
if (de->rec_len < 8 || de->rec_len % 8 != 0 ||
de->rec_len < de->name_len + 8 ||
(de->rec_len + (off_t) filp->f_pos - 1) / 1024 > ((off_t) filp->f_pos / 1024)) {
......@@ -106,8 +118,8 @@ static int ext_readdir(struct inode * inode, struct file * filp,
put_fs_long(de->inode,&dirent->d_ino);
put_fs_byte(0,i+dirent->d_name);
put_fs_word(i,&dirent->d_reclen);
brelse(bh);
return i;
ret = ROUND_UP(NAME_OFFSET(dirent)+i+1);
break;
}
}
de = (struct ext_dir_entry *) ((char *) de
......@@ -115,5 +127,5 @@ static int ext_readdir(struct inode * inode, struct file * filp,
}
brelse(bh);
}
return 0;
return ret;
}
......@@ -22,6 +22,9 @@
#include <linux/sched.h>
#include <linux/stat.h>
#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
#define ROUND_UP(x) (((x)+3) & ~3)
static int ext2_dir_read (struct inode * inode, struct file * filp,
char * buf, int count)
{
......@@ -98,17 +101,21 @@ static int ext2_readdir (struct inode * inode, struct file * filp,
struct dirent * dirent, int count)
{
unsigned long offset, blk;
int i, num;
int i, num, stored, dlen;
struct buffer_head * bh, * tmp, * bha[16];
struct ext2_dir_entry * de;
struct super_block * sb;
int err;
int err, version;
if (!inode || !S_ISDIR(inode->i_mode))
return -EBADF;
sb = inode->i_sb;
while (filp->f_pos < inode->i_size) {
offset = filp->f_pos & (sb->s_blocksize - 1);
stored = 0;
bh = NULL;
offset = filp->f_pos & (sb->s_blocksize - 1);
while (count > 0 && !stored && filp->f_pos < inode->i_size) {
blk = (filp->f_pos) >> EXT2_BLOCK_SIZE_BITS(sb);
bh = ext2_bread (inode, blk, 0, &err);
if (!bh) {
......@@ -135,39 +142,78 @@ static int ext2_readdir (struct inode * inode, struct file * filp,
}
}
de = (struct ext2_dir_entry *) (offset + bh->b_data);
while (offset < sb->s_blocksize && filp->f_pos < inode->i_size) {
revalidate:
/* If the dir block has changed since the last call to
readdir(2), then we might be pointing to an invalid dirent
right now. Scan from the start of the block to make
sure. */
for (i = 0; i < sb->s_blocksize && i < offset; ) {
de = (struct ext2_dir_entry *) (bh->b_data + i);
/* It's too expensive to do a full dirent test
* each time round this loop, but we do have
* to test at least that it is non-zero. A
* failure will be detected in the dirent test
* below. */
if (de->rec_len < EXT2_DIR_REC_LEN(1))
break;
i += de->rec_len;
}
offset = i;
filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1)) | offset;
while (count > 0 && filp->f_pos < inode->i_size
&& offset < sb->s_blocksize) {
de = (struct ext2_dir_entry *) (bh->b_data + offset);
if (!ext2_check_dir_entry ("ext2_readdir", inode, de,
bh, offset)) {
/* On error, skip the f_pos to the next block. */
filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1))
+ sb->s_blocksize;
brelse (bh);
return 0;
return stored;
}
offset += de->rec_len;
filp->f_pos += de->rec_len;
if (de->inode) {
memcpy_tofs (dirent->d_name, de->name,
de->name_len);
dlen = ROUND_UP(NAME_OFFSET(dirent)
+ de->name_len + 1);
/* Old libc libraries always use a count of 1. */
if (count == 1 && !stored)
count = dlen;
if (count < dlen) {
count = 0;
break;
}
/* We might block in the next section
* if the data destination is
* currently swapped out. So, use a
* version stamp to detect whether or
* not the directory has been modified
* during the copy operation. */
version = inode->i_version;
i = de->name_len;
memcpy_tofs (dirent->d_name, de->name, i);
put_fs_long (de->inode, &dirent->d_ino);
put_fs_byte (0, de->name_len + dirent->d_name);
put_fs_word (de->name_len, &dirent->d_reclen);
put_fs_byte (0, dirent->d_name + i);
put_fs_word (i, &dirent->d_reclen);
put_fs_long (dlen, &dirent->d_off);
if (version != inode->i_version)
goto revalidate;
dcache_add(inode, de->name, de->name_len,
de->inode);
i = de->name_len;
brelse (bh);
if (!IS_RDONLY(inode)) {
inode->i_atime = CURRENT_TIME;
inode->i_dirt = 1;
}
return i;
stored += dlen;
count -= dlen;
((char *) dirent) += dlen;
}
de = (struct ext2_dir_entry *) ((char *) de +
de->rec_len);
offset += de->rec_len;
filp->f_pos += de->rec_len;
}
offset = 0;
brelse (bh);
}
if (!IS_RDONLY(inode)) {
inode->i_atime = CURRENT_TIME;
inode->i_dirt = 1;
}
return 0;
return stored;
}
......@@ -318,6 +318,7 @@ static struct buffer_head * ext2_add_entry (struct inode * dir,
*/
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
dir->i_dirt = 1;
dir->i_version = ++event;
mark_buffer_dirty(bh, 1);
*res_dir = de;
*err = 0;
......@@ -923,8 +924,10 @@ static int do_ext2_rename (struct inode * old_dir, const char * old_name,
goto start_up;
try_again:
if (new_bh && new_de)
if (new_bh && new_de) {
ext2_delete_entry(new_de, new_bh);
new_dir->i_version = ++event;
}
brelse (old_bh);
brelse (new_bh);
brelse (dir_bh);
......@@ -1002,6 +1005,7 @@ static int do_ext2_rename (struct inode * old_dir, const char * old_name,
&retval);
if (!new_bh)
goto end_rename;
new_dir->i_version = ++event;
/*
* sanity checking before doing the rename - avoid races
*/
......@@ -1015,7 +1019,6 @@ static int do_ext2_rename (struct inode * old_dir, const char * old_name,
* ok, that's it
*/
new_de->inode = old_inode->i_ino;
new_dir->i_version = ++event;
dcache_add(new_dir, new_de->name, new_de->name_len, new_de->inode);
retval = ext2_delete_entry (old_de, old_bh);
if (retval == -ENOENT)
......
......@@ -117,6 +117,9 @@
/* notation */
#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
#define ROUND_UP(x) (((x)+3) & ~3)
#define little_ushort(x) (*(unsigned short *) &(x))
typedef void nonconst;
......@@ -1345,13 +1348,13 @@ static int hpfs_readdir(struct inode *inode, struct file *filp,
case 0:
write_one_dirent(dirent, ".", 1, inode->i_ino, lc);
filp->f_pos = -1;
return 1;
return ROUND_UP(NAME_OFFSET(dirent) + 2);
case -1:
write_one_dirent(dirent, "..", 2,
inode->i_hpfs_parent_dir, lc);
filp->f_pos = 1;
return 2;
return ROUND_UP(NAME_OFFSET(dirent) + 3);
case -2:
return 0;
......@@ -1371,7 +1374,7 @@ static int hpfs_readdir(struct inode *inode, struct file *filp,
write_one_dirent(dirent, de->name, namelen, ino, lc);
brelse4(&qbh);
return namelen;
return ROUND_UP(NAME_OFFSET(dirent) + namelen + 1);
}
}
......
......@@ -22,6 +22,9 @@
#include <linux/sched.h>
#include <linux/locks.h>
#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
#define ROUND_UP(x) (((x)+3) & ~3)
static int isofs_readdir(struct inode *, struct file *, struct dirent *, int);
static struct file_operations isofs_dir_operations = {
......@@ -228,7 +231,7 @@ static int isofs_readdir(struct inode * inode, struct file * filp,
put_fs_byte(0,i+dirent->d_name);
put_fs_word(i,&dirent->d_reclen);
brelse(bh);
return i;
return ROUND_UP(NAME_OFFSET(dirent) + i + 1);
}
}
/* We go here for any condition we cannot handle. We also drop through
......
......@@ -13,6 +13,9 @@
#include <linux/minix_fs.h>
#include <linux/stat.h>
#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
#define ROUND_UP(x) (((x)+3) & ~3)
static int minix_dir_read(struct inode * inode, struct file * filp, char * buf, int count)
{
return -EISDIR;
......@@ -57,7 +60,8 @@ struct inode_operations minix_dir_inode_operations = {
static int minix_readdir(struct inode * inode, struct file * filp,
struct dirent * dirent, int count)
{
unsigned int offset,i;
unsigned int offset,i,ret;
int version;
char c;
struct buffer_head * bh;
struct minix_dir_entry * de;
......@@ -68,17 +72,19 @@ static int minix_readdir(struct inode * inode, struct file * filp,
info = &inode->i_sb->u.minix_sb;
if (filp->f_pos & (info->s_dirsize - 1))
return -EBADF;
while (filp->f_pos < inode->i_size) {
ret = 0;
while (!ret && filp->f_pos < inode->i_size) {
offset = filp->f_pos & 1023;
bh = minix_bread(inode,(filp->f_pos)>>BLOCK_SIZE_BITS,0);
if (!bh) {
filp->f_pos += 1024-offset;
continue;
}
while (offset < 1024 && filp->f_pos < inode->i_size) {
while (!ret && offset < 1024 && filp->f_pos < inode->i_size) {
de = (struct minix_dir_entry *) (offset + bh->b_data);
offset += info->s_dirsize;
filp->f_pos += info->s_dirsize;
retry:
if (de->inode) {
for (i = 0; i < info->s_namelen; i++)
if ((c = de->name[i]) != 0)
......@@ -86,15 +92,17 @@ static int minix_readdir(struct inode * inode, struct file * filp,
else
break;
if (i) {
version = inode->i_version;
put_fs_long(de->inode,&dirent->d_ino);
put_fs_byte(0,i+dirent->d_name);
put_fs_word(i,&dirent->d_reclen);
brelse(bh);
return i;
if (version != inode->i_version)
goto retry;
ret = ROUND_UP(NAME_OFFSET(dirent)+i+1);
}
}
}
brelse(bh);
}
return 0;
return ret;
}
......@@ -195,6 +195,7 @@ static int minix_add_entry(struct inode * dir,
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
for (i = 0; i < info->s_namelen ; i++)
de->name[i] = (i < namelen) ? name[i] : 0;
dir->i_version = ++event;
mark_buffer_dirty(bh, 1);
*res_dir = de;
break;
......@@ -470,11 +471,12 @@ int minix_rmdir(struct inode * dir, const char * name, int len)
if (inode->i_nlink != 2)
printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink);
de->inode = 0;
dir->i_version = ++event;
mark_buffer_dirty(bh, 1);
inode->i_nlink=0;
inode->i_dirt=1;
dir->i_nlink--;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
dir->i_nlink--;
dir->i_dirt=1;
retval = 0;
end_rmdir:
......@@ -523,6 +525,7 @@ int minix_unlink(struct inode * dir, const char * name, int len)
inode->i_nlink=1;
}
de->inode = 0;
dir->i_version = ++event;
mark_buffer_dirty(bh, 1);
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
dir->i_dirt = 1;
......@@ -768,8 +771,10 @@ static int do_minix_rename(struct inode * old_dir, const char * old_name, int ol
new_de->inode = old_inode->i_ino;
old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
old_dir->i_dirt = 1;
old_dir->i_version = ++event;
new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
new_dir->i_dirt = 1;
new_dir->i_version = ++event;
if (new_inode) {
new_inode->i_nlink--;
new_inode->i_ctime = CURRENT_TIME;
......
......@@ -14,6 +14,9 @@
#include <linux/stat.h>
#include <linux/string.h>
#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
#define ROUND_UP(x) (((x)+3) & ~3)
static int msdos_dir_read(struct inode * inode,struct file * filp, char * buf,int count)
{
......@@ -73,7 +76,7 @@ int msdos_readdir(
put_fs_long(MSDOS_ROOT_INO,&dirent->d_ino);
put_fs_byte(0,dirent->d_name+i);
put_fs_word(i,&dirent->d_reclen);
return i;
return ROUND_UP(NAME_OFFSET(dirent) + i + 1);
}
}
if (filp->f_pos & (sizeof(struct msdos_dir_entry)-1)) return -ENOENT;
......@@ -110,7 +113,7 @@ int msdos_readdir(
memcpy_tofs(dirent->d_name,bufname,i+1);
put_fs_word(i,&dirent->d_reclen);
brelse(bh);
return i;
return ROUND_UP(NAME_OFFSET(dirent) + i + 1);
}
}
}
......
......@@ -18,6 +18,9 @@
#include <asm/segment.h> /* for fs functions */
#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
#define ROUND_UP(x) (((x)+3) & ~3)
static int nfs_dir_read(struct inode *, struct file *filp, char *buf,
int count);
static int nfs_readdir(struct inode *, struct file *, struct dirent *, int);
......@@ -153,7 +156,7 @@ static int nfs_readdir(struct inode *inode, struct file *filp,
put_fs_long(entry->fileid, &dirent->d_ino);
put_fs_word(i, &dirent->d_reclen);
filp->f_pos = entry->cookie;
return i;
return ROUND_UP(NAME_OFFSET(dirent)+i+1);
}
return 0;
}
......
......@@ -92,7 +92,8 @@ static int proc_fd_dupf(struct inode * inode, struct file * f)
new_f->f_count++;
current->files->fd[fd] = new_f;
f->f_count--;
if (!--f->f_count)
iput(f->f_inode);
return 0;
}
......
......@@ -13,8 +13,14 @@
#include <asm/segment.h>
/*
* Count is not yet used: but we'll probably support reading several entries
* at once in the future. Use count=1 in the library for future expansions.
* Count is now a supported feature, but currently only the ext2fs
* uses it. A count value of 1 is supported for compatibility with
* earlier libraries, but larger values are supported: count should
* indicate the total buffer space available for filling with dirents.
* The d_off entry in the dirents will then indicate the offset from
* each dirent to the next, and the return value will indicate the
* number of bytes written. All dirents will be written at
* word-aligned addresses. [sct Oct 1994]
*/
asmlinkage int sys_readdir(unsigned int fd, struct dirent * dirent, unsigned int count)
{
......@@ -62,8 +68,10 @@ asmlinkage int sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
}
if (tmp < 0)
return -EINVAL;
file->f_pos = tmp;
file->f_reada = 0;
if (tmp != file->f_pos) {
file->f_pos = tmp;
file->f_reada = 0;
}
return file->f_pos;
}
......
......@@ -20,6 +20,9 @@
#include <linux/sysv_fs.h>
#include <linux/stat.h>
#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
#define ROUND_UP(x) (((x)+3) & ~3)
static int sysv_dir_read(struct inode * inode, struct file * filp, char * buf, int count)
{
return -EISDIR;
......@@ -100,7 +103,7 @@ static int sysv_readdir(struct inode * inode, struct file * filp,
put_fs_byte(0,i+dirent->d_name);
put_fs_word(i,&dirent->d_reclen);
brelse(bh);
return i;
return ROUND_UP(NAME_OFFSET(dirent)+i+1);
}
}
}
......
......@@ -19,6 +19,9 @@
#include "xiafs_mac.h"
#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
#define ROUND_UP(x) (((x)+3) & ~3)
static int xiafs_dir_read(struct inode *, struct file *, char *, int);
static int xiafs_readdir(struct inode *, struct file *, struct dirent *, int);
......@@ -65,7 +68,7 @@ static int xiafs_dir_read(struct inode * inode,
static int xiafs_readdir(struct inode * inode,
struct file * filp, struct dirent * dirent, int count)
{
u_int offset, i;
u_int offset, i,ret;
struct buffer_head * bh;
struct xiafs_direct * de;
......@@ -73,15 +76,24 @@ static int xiafs_readdir(struct inode * inode,
return -EBADF;
if (inode->i_size & (XIAFS_ZSIZE(inode->i_sb) - 1) )
return -EBADF;
while (filp->f_pos < inode->i_size) {
ret = 0;
while (!ret && filp->f_pos < inode->i_size) {
offset = filp->f_pos & (XIAFS_ZSIZE(inode->i_sb) - 1);
bh = xiafs_bread(inode, filp->f_pos >> XIAFS_ZSIZE_BITS(inode->i_sb),0);
if (!bh) {
filp->f_pos += XIAFS_ZSIZE(inode->i_sb)-offset;
continue;
}
for (i = 0; i < XIAFS_ZSIZE(inode->i_sb) && i < offset; ) {
de = (struct xiafs_direct *) (bh->b_data + i);
if (!de->d_rec_len)
break;
i += de->d_rec_len;
}
offset = i;
de = (struct xiafs_direct *) (offset + bh->b_data);
while (offset < XIAFS_ZSIZE(inode->i_sb) && filp->f_pos < inode->i_size) {
while (!ret && offset < XIAFS_ZSIZE(inode->i_sb) && filp->f_pos < inode->i_size) {
if (de->d_ino > inode->i_sb->u.xiafs_sb.s_ninodes ||
de->d_rec_len < 12 ||
(char *)de+de->d_rec_len > XIAFS_ZSIZE(inode->i_sb)+bh->b_data ||
......@@ -100,12 +112,12 @@ static int xiafs_readdir(struct inode * inode,
put_fs_byte(0,i+dirent->d_name);
put_fs_long(de->d_ino,&dirent->d_ino);
put_fs_word(i,&dirent->d_reclen);
brelse(bh);
if (!IS_RDONLY (inode)) {
inode->i_atime=CURRENT_TIME;
inode->i_dirt=1;
}
return i;
ret = ROUND_UP(NAME_OFFSET(dirent)+i+1);
break;
}
de = (struct xiafs_direct *) (offset + bh->b_data);
}
......
......@@ -71,7 +71,6 @@ struct hd_geometry {
#define HDIO_SETUNMASKINTR 0x303
#define HDIO_GETMULTCOUNT 0x304
#define HDIO_SETMULTCOUNT 0x305
#define HDIO_SETFEATURE 0x306
#define HDIO_GETIDENTITY 0x307
#endif
......
......@@ -289,6 +289,7 @@ extern void stop_tty(struct tty_struct * tty);
extern void start_tty(struct tty_struct * tty);
extern int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc);
extern int tty_register_driver(struct tty_driver *driver);
extern int tty_unregister_driver(struct tty_driver *driver);
extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp,
int buflen);
......
......@@ -25,6 +25,7 @@
#include <linux/module.h>
#include <linux/termios.h>
#include <linux/tqueue.h>
#include <linux/tty.h>
#include <linux/serial.h>
#ifdef CONFIG_INET
#include <linux/netdevice.h>
......@@ -91,6 +92,9 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */
X(unregister_chrdev),
X(register_blkdev),
X(unregister_blkdev),
X(tty_register_driver),
X(tty_unregister_driver),
X(tty_std_termios),
/* block device driver support */
X(block_read),
......
......@@ -83,6 +83,7 @@
* Matt Dillon : Yet more small nasties remove from the TCP code
* (Be very nice to this man if tcp finally works 100%) 8)
* Alan Cox : BSD accept semantics.
* Peter De Schrijver : ENOTCONN check missing in tcp_sendto().
*
*
* To Fix:
......@@ -1221,15 +1222,17 @@ static int tcp_sendto(struct sock *sk, unsigned char *from,
{
if (flags & ~(MSG_OOB|MSG_DONTROUTE))
return -EINVAL;
if (addr_len < sizeof(*addr))
return(-EINVAL);
if (!tcp_connected(sk->state))
return -ENOTCONN;
if (addr_len < sizeof(*addr))
return -EINVAL;
if (addr->sin_family && addr->sin_family != AF_INET)
return(-EINVAL);
return -EINVAL;
if (addr->sin_port != sk->dummy_th.dest)
return(-EISCONN);
return -EISCONN;
if (addr->sin_addr.s_addr != sk->daddr)
return(-EISCONN);
return(tcp_write(sk, from, len, nonblock, flags));
return -EISCONN;
return tcp_write(sk, from, len, nonblock, flags);
}
......@@ -2238,7 +2241,7 @@ static void tcp_close(struct sock *sk, int timeout)
/* The +1 is not needed because the FIN takes up seq
is not read!!! */
if(skb->len > 0 && after(skb->h.th->seq + skb->len , sk->copied_seq))
need_reset = 1;
need_reset = 0;
kfree_skb(skb, FREE_READ);
}
if(sk->debug)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment