From 5f50b72d630fe6f537e2653b3ad3cfc1f9052338 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:09:40 -0500 Subject: [PATCH] Import 1.1.52 --- CREDITS | 227 +++++++--- Makefile | 2 +- arch/i386/entry.S | 1 - drivers/block/blk.h | 3 +- drivers/block/floppy.c | 923 ++++++++++++++++++++++----------------- drivers/block/hd.c | 62 ++- drivers/block/ramdisk.c | 29 +- drivers/char/console.c | 3 +- drivers/char/lp.c | 67 ++- drivers/char/n_tty.c | 33 +- drivers/char/tty_io.c | 13 + drivers/char/tty_ioctl.c | 21 +- drivers/net/plip.c | 13 +- drivers/sound/dma.h | 266 ----------- fs/buffer.c | 27 +- fs/exec.c | 4 +- fs/ext/dir.c | 2 +- fs/ext2/file.c | 32 +- fs/hpfs/hpfs.h | 6 +- fs/locks.c | 2 +- fs/nfs/file.c | 133 ++++-- fs/nfs/mmap.c | 2 +- fs/nfs/proc.c | 269 +++++++----- fs/nfs/sock.c | 32 +- fs/nfs/symlink.c | 47 +- fs/super.c | 51 ++- fs/sysv/README | 2 +- fs/sysv/inode.c | 4 + include/linux/fd.h | 4 +- include/linux/fdreg.h | 2 + include/linux/hdreg.h | 21 +- include/linux/lp.h | 13 - include/linux/ncp.h | 106 ----- include/linux/nfs_fs.h | 7 +- include/linux/tty.h | 1 + kernel/bios32.c | 8 + kernel/itimer.c | 21 +- kernel/sched.c | 11 + kernel/sys.c | 14 +- kernel/sys_call.S | 545 ----------------------- kernel/time.c | 47 +- kernel/vsprintf.c | 2 + mm/memory.c | 12 +- net/inet/icmp.c | 2 +- net/inet/ncp.h | 26 -- net/inet/route.c | 2 +- 46 files changed, 1369 insertions(+), 1751 deletions(-) delete mode 100644 drivers/sound/dma.h delete mode 100644 include/linux/ncp.h delete mode 100644 kernel/sys_call.S delete mode 100644 net/inet/ncp.h diff --git a/CREDITS b/CREDITS index 103181f245a6..a0252feb21b0 100644 --- a/CREDITS +++ b/CREDITS @@ -7,6 +7,10 @@ Linus ---------- +N: Werner Almesberger +E: almesber@bernina.ethz.ch +D: dosfs, LILO, some fd features, various other hacks here and there + N: Krishna Balasubramanian E: balasub@cis.ohio-state.edu D: Wrote SYS V IPC (part of standard kernel since 0.99.10) @@ -38,8 +42,9 @@ E: becker@cesdis.gsfc.nasa.gov D: General low-level networking hacker D: Most of the ethercard drivers D: Original author of the NFS server -S: 17100 Science Drive -S: Bowie, Maryland 20715 +S: USRA Center of Excellence in Space Data and Information Sciences +S: Code 930.5, Goddard Space Flight Center +S: Greenbelt, Maryland 20771 S: USA N: Stephen R. van den Berg (AKA BuGless) @@ -48,11 +53,11 @@ D: General kernel, gcc, and libc hacker D: Specialisation: tweaking, ensuring portability, tweaking, cleaning, D: tweaking and occasionally debugging :-) S: Bouwensstraat 22 -S: 6369 BG Simpelveld +S: 6369 BG Simpelveld S: The Netherlands N: Hennus Bergman -E: hennus@sky.nl.mugnet.org [My uucp-fed Linux box at home] +E: hennus@sky.nl.mugnet.org [My uucp-fed Linux box at home] D: Author and maintainer of the QIC-02 tape driver S: The Netherlands @@ -72,7 +77,7 @@ N: John Boyd E: boyd@cis.ohio-state.edu D: Co-author of wd7000 SCSI driver S: 101 Curl Drive #591 -S: Columbus, Ohio 43210 +S: Columbus, Ohio 43210 S: USA N: Andries Brouwer @@ -82,12 +87,21 @@ S: Bessemerstraat 21 S: Amsterdam S: The Netherlands +N: Michael Callahan +E: callahan@maths.ox.ac.uk +D: PPP for Linux +S: The Mathematical Institute +S: 25-29 St Giles +S: Oxford +S: United Kingdom + N: Remy Card E: Remy.Card@masi.ibp.fr D: Extended file system designer and developer D: Second extended file system designer and developer S: Institut Blaise Pascal -S: 4 Place Jussieu, 75252 Paris Cedex 05 +S: 4 Place Jussieu +S: 75252 Paris Cedex 05 S: France N: Ed Carp @@ -95,14 +109,14 @@ E: ecarp@netcom.com D: uucp, elm, pine, pico port D: cron, at(1) developer S: 48287 Sawleaf -S: Fremont, California 94539 +S: Fremont, California 94539 S: USA N: Raymond Chen E: raymondc@microsoft.com D: Author of Configure script -S: 14509 NE 39th St, #1096 -S: Bellevue WA 98007 +S: 14509 NE 39th Street #1096 +S: Bellevue, Washington 98007 S: USA N: Alan Cox @@ -113,7 +127,6 @@ E: GW4PTS@GB7SWN (packet radio) D: NET2Debugged author D: Network layer debugging D: AX.25 & IPX alpha releases -S: N: Laurence Culhane E: loz@holmes.demon.co.uk @@ -121,12 +134,21 @@ D: Wrote the initial alpha SLIP code S: 81 Hood Street S: Northampton S: NN1 3QT -S: England +S: United Kingdom N: Wayne Davison E: davison@borland.com D: Second extended file system co-designer +N: Todd J. Derr +E: tjd@cs.pitt.edu +D: maintainer of dual-monitor patches for 1.0+ +D: MouseMan driver for selection +S: Department of Computer Science +S: University of Pittsburgh +S: Pittsburgh, Pennsylvania 15260 +S: USA + N: Thomas Dunbar E: tdunbar@vtaix.cc.vt.edu D: TeX & METAFONT hacking/maintenance @@ -144,19 +166,20 @@ S: 47807 Krefeld S: Germany N: Drew Eckhardt -E: drew@cs.Colorado.EDU +E: drew@Colorado.EDU D: SCSI code D: Assorted snippets elsewhere D: Boot sector "..." printing -S: 538 West Laurell Court -S: Louisville, Colorado 80027 +S: 2255 Spruce +S: Boulder, Colorado 80302 S: USA N: Bjorn Ekwall E: bj0rn@blox.se -D: Driver for the D-Link parallel port Ethernet adapter +D: Extended support for loadable modules +D: D-Link pocket adapter drivers S: Myrstuguv. 83 -S: S-143 32 VARBY +S: S-143 32 VARBY S: Sweden N: Doug Evans @@ -189,9 +212,15 @@ D: The Linux Support Team Erlangen N: Lawrence Foard E: entropy@world.std.com D: Floppy track reading, fs code -S: Suite #108 -S: 217 Park Ave. -S: Worcester Ma 01609 +S: 217 Park Avenue, Suite 108 +S: Worcester, Massachusetts 01609 +S: USA + +N: Karl Fogel +E: kfogel@cs.oberlin.edu +D: Contributor, Linux User's Guide +S: 1123 North Oak Park Avenue +S: Oak Park, Illinois 60302 S: USA N: Nigel Gamble @@ -201,12 +230,19 @@ S: 301 Norwood Terrace, Apartment N226 S: Boca Raton, Florida 33431-6588 S: USA +N: Jacques Gelinas +E: jacques@solucorp.qc.ca +D: Author of the Umsdos file system +S: 1326 De Val-Brillant +S: Laval, Quebec +S: Canada H7Y 1V9 + N: David Gentzel E: gentzel@nova.enet.dec.com D: BusLogic driver and original UltraStor driver S: Whitfield Software Services S: 631 Idlewood Avenue -S: Carnegie, Pennsylvania 15106-1126 +S: Carnegie, Pennsylvania 15106-1126 S: USA N: Philip Gladstone @@ -220,13 +256,21 @@ S: Augartenstrasse 40 S: D - 76137 Karlsruhe S: Germany +N: Greg Hankins +E: gregh@cc.gatech.edu +D: fixed keyboard driver to separate LED and locking status +S: 25360 Georgia Tech Station +S: Atlanta, Georgia 30332 +S: USA + N: Andrew Haylett E: ajh@gec-mrc.co.uk D: Selection mechanism S: GEC-Marconi Research Centre S: West Hanningfield Road -S: Great Baddow, Essex CM2 8HN -S: UK +S: Great Baddow +S: CM2 8HN +S: United Kingdom N: Michael Hipp E: mhipp@student.uni-tuebingen.de @@ -236,11 +280,12 @@ S: D - 72072 Tuebingen S: Germany N: Dirk Hohndel -E: hohndel@informatik.uni-wuerzburg.de -D: XFree86 -S: Universit"at W"urzburg, LS Informatik I -S: Am Hubland, 97218 W"urzburg -S: Germany +E: hohndel@aib.com +D: The XFree86[tm] Project +S: AIB Software Corporation +S: 46030 Manekin Plaza, Suite 160 +S: Dulles, Virginia 20166 +S: USA N: Nick Holloway E: alfie@dcs.warwick.ac.uk @@ -250,7 +295,7 @@ S: Department of Computer Science S: University of Warwick S: Coventry S: CV4 7AL -S: UK +S: United Kingdom N: Ron Holt E: ron@novell.com @@ -270,6 +315,31 @@ S: Panoramastrasse 18 S: D-69126 Heidelberg S: Germany +N: Ian Jackson +E: iwj10@cus.cam.ac.uk +E: ijackson@nyx.cs.du.edu +D: FAQ maintainer and poster of the daily postings +D: FSSTND group member +D: Debian core team member and maintainer of several Debian packages +S: 2 Lexington Close +S: Cambridge +S: CB3 0DS +S: United Kingdom + +N: Mike Jagdis +E: jaggy@purplet.demon.co.uk +E: Mike.Jagdis@purplet.demon.co.uk +D: iBCS personalities, socket and X interfaces, x.out loader, syscalls... +D: Purple Distribution maintainer +D: UK FidoNet support +D: ISODE && PP +D: Kernel and device driver hacking +S: 280 Silverdale Road +S: Earley +S: Reading +S: RG6 2NU +S: United Kingdom + N: Michael K. Johnson E: johnsonm@sunsite.unc.edu D: The Linux Documentation Project @@ -288,7 +358,7 @@ D: NET-2 D: Drivers D: Kernel cleanups S: Hoefbladhof 27 -S: 2215 DV Voorhout +S: 2215 DV Voorhout S: The Netherlands N: Olaf Kirch @@ -313,13 +383,28 @@ N: Bas Laarhoven E: bas@vimec.nl D: Loadable modules and ftape driver S: Mr. v. Boemellaan 39 -S: NL-5237 KA 's-Hertogenbosch +S: NL-5237 KA 's-Hertogenbosch S: The Netherlands +N: Kevin Lentin +E: kevinl@cs.monash.edu.au +D: NCR53C400/T130B SCSI extension to NCR5380 driver. +S: 18 Board Street +S: Doncaster VIC 3108 +S: Australia + +N: Mark Lord +E: mlord@bnr.ca +E: mlord@achilles.net +D: IDE drive support in hd.c +S: 33 Ridgefield Cr +S: Nepean, Ontario +S: Canada K2H 6S3 + N: Warner Losh E: imp@boulder.parcplace.com D: Provided OI/OB for Linux, general hacker -S: 4909 Pearl East Circle Suite 200 +S: 4909 Pearl East Circle, Suite 200 S: Boulder, Colorado 80303 S: USA @@ -352,8 +437,8 @@ E: pat@it.com.au D: 8 bit XT hard disk driver D: Miscellaneous ST0x, TMC-8xx and other SCSI hacking S: 25 McMillan Street -S: Victoria Park, 6100 -S: Western Australia +S: Victoria Park 6100 +S: Australia N: John A. Martin E: jmartin@csc.com @@ -366,6 +451,15 @@ S: 1100 West Street S: Laurel, Maryland 20707-3587 S: USA +N: Kevin E. Martin +E: martin@cs.unc.edu +D: Developed original accelerated X servers included in XFree86 +D: XF86_Mach64 (forthcoming -- please don't ask when) +D: XF86_Mach32 +D: XF86_Mach8 +D: XF86_8514 +D: cfdisk (curses based disk partitioning program) + N: Bradley McLean E: brad@bradpc.gaylord.com D: Device driver hacker @@ -411,7 +505,9 @@ D: Linux Projects Map, Linux Commercial-HOWTO D: general Linux publicity in Germany, vacation port D: UUCP and CNEWS binary packages for LST S: Editorial Board iX Mag -S: Helstorfer Str. 7, D-30625 Hannover +S: Helstorfer Str. 7 +S: D-30625 Hannover +S: Germany N: Corey Minyard E: minyard@wf-rch.cirr.com @@ -431,7 +527,7 @@ N: Ian A. Murdock E: imurdock@gnu.ai.mit.edu D: Creator of Debian distribution S: 30 White Tail Lane -S: Lafayette, Indiana 47906 +S: Lafayette, Indiana 47905 S: USA N: Johan Myreen @@ -442,6 +538,7 @@ S: FIN-00330 Helsingfors S: Finland N: David C. Niemi +E: niemidc@clark.net E: niemidc@slma.com D: FSSTND, The XFree86 Project D: DMA memory support, floppy driver @@ -449,6 +546,16 @@ S: 2364 Old Trail Drive S: Reston, Virginia 22091 S: USA +N: Michael O'Reilly +E: michael@iinet.com.au +E: oreillym@tartarus.uwa.edu.au +D: Wrote the original dynamic sized disk cache stuff. I think the only +D: part that remains is the GFP_KERNEL et al #defines. :) +S: 192 Nichsolson Road +S: Subiaco, 6008 +S: Perth, Western Australia +S: Australia + N: Kai Petzke E: wpp@marie.physik.tu-berlin.de D: Driver for Laser Magnetic Storage CD-ROM @@ -463,11 +570,10 @@ E: snprobst@immd4.informatik.uni-erlangen.de D: The Linux Support Team Erlangen N: Daniel Quinlan -E: quinlan@bucknell.edu +E: quinlan@yggdrasil.com D: FSSTND Coordinator -S: Box C3529 -S: Bucknell University -S: Lewisburg, Pennsylvania 17837 +S: 816 Saratoga Avenue, Apartment M208 +S: San Jose, California 95129 S: USA N: Florian La Roche @@ -481,7 +587,7 @@ S: Germany N: Stephen Rothwell E: sfr@pdact.pd.necisa.oz.au D: Boot/setup/build work for setup > 2K -S: 59 Bugden Ave +S: 59 Bugden Avenue S: Gowrie ACT 2904 S: Australia @@ -510,6 +616,15 @@ S: 620 Park View Drive #206 S: Santa Clara, California 95054 S: USA +N: Rick Sladkey +E: jrs@world.std.com +D: utility hacker: Emacs, NFS server, mount, kmem-ps, UPS debugger, strace, GDB +D: library hacker: RPC, profil(3), realpath(3), regexp.h +D: kernel hacker: unnamed block devs, NFS client, fast select, precision timer +S: 24 Avon Place +S: Arlington, Massachusetts 02174 +S: USA + N: Chris Smith E: csmith@convex.com D: HPFS filesystem @@ -521,7 +636,7 @@ E: drew@lethe.north.net D: iBCS2 developer S: 22 Irvington Cres. S: Willowdale, Ontario -S: Canada, M2N 2Z1 +S: Canada M2N 2Z1 N: Tommy Thorn E: Tommy.Thorn@daimi.aau.dk @@ -579,8 +694,9 @@ S: Dept. of Computer Science S: University of Edinburgh S: JCMB, The King's Buildings S: Mayfield Road -S: Edinburgh EH9 3JZ -S: Scotland, UK +S: Edinburgh +S: EH9 3JZ +S: United Kingdom N: Thomas Uhl E: uhl@sun1.rz.fh-heilbronn.de @@ -591,12 +707,22 @@ S: Obere Heerbergstrasse 17 S: 97078 Wuerzburg S: Germany +N: Jeffrey A. Uphoff +E: juphoff@nrao.edu +E: jeff.uphoff@linux.org +D: 'dip' contributor. +D: AIPS port, astronomical community support. +S: National Radio Astronomy Observatory +S: 520 Edgemont Road +S: Charlottesville, Virginia 22903 +S: USA + N: Patrick Volkerding E: volkerdi@ftp.cdrom.com D: Produced the Slackware distribution, updated the SVGAlib D: patches for ghostscript, worked on color 'ls', etc. S: 301 15th Street S. -S: Moorhead, MN 56560 +S: Moorhead, Minnesota 56560 S: USA N: Juergen Weigert @@ -611,7 +737,7 @@ D: HOWTO coordinator and writer D: Maintainer of sunsite.unc.edu Linux doc archives D: Moderator, comp.os.linux.announce S: 205 Gray Street NE -S: Wilson, North Carolina 27893 +S: Wilson, North Carolina 27893 S: USA @@ -635,7 +761,7 @@ E: gunter@mbfys.kun.nl D: Some bug fixes in the polling printer driver (lp.c) S: University of Nijmegen S: Geert-Grooteplein Noord 21 -S: 6525 EZ Nijmegen +S: 6525 EZ Nijmegen S: The Netherlands N: Lars Wirzenius @@ -655,8 +781,8 @@ S: Finland N: Roger E. Wolff E: wolff@dutecai.et.tudelft.nl D: Written kmalloc/kfree -S: Oosterstraat 23 -S: 2611 TT Delft +S: Oosterstraat 23 +S: 2611 TT Delft S: The Netherlands N: Frank Xia @@ -668,15 +794,14 @@ S: USA N: Eric Youngdale E: ericy@cais.com -E: eric@tantalus.nrl.navy.mil D: General kernel hacker -D: SCSI, iso9660, ELF, ibcs2, clustering in buffer cache, generalized mmap. +D: SCSI iso9660 and ELF S: 17 Canterbury Square #101 S: Alexandria, Virginia 22304 S: USA N: Orest Zborowski -E: orestz@microsoft.com +E: orestz@eskimo.com D: XFree86 and kernel development S: 1507 145th Place SE #B5 S: Bellevue, Washington 98007 diff --git a/Makefile b/Makefile index 43d3c82325e5..2915d6e47726 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 1 -SUBLEVEL = 51 +SUBLEVEL = 52 ARCH = i386 diff --git a/arch/i386/entry.S b/arch/i386/entry.S index 41147f308388..b6c2df54a973 100644 --- a/arch/i386/entry.S +++ b/arch/i386/entry.S @@ -541,5 +541,4 @@ _sys_call_table: .long _sys_setfsuid .long _sys_setfsgid .long _sys_llseek /* 140 */ - .space (NR_syscalls-139)*4 .space (NR_syscalls-140)*4 diff --git a/drivers/block/blk.h b/drivers/block/blk.h index c9f09bd2bcf3..95a8fb2068d8 100644 --- a/drivers/block/blk.h +++ b/drivers/block/blk.h @@ -75,14 +75,13 @@ extern unsigned long xd_init(unsigned long mem_start, unsigned long mem_end); #elif (MAJOR_NR == FLOPPY_MAJOR) -static void floppy_on(unsigned int nr); static void floppy_off(unsigned int nr); #define DEVICE_NAME "floppy" #define DEVICE_INTR do_floppy #define DEVICE_REQUEST do_fd_request #define DEVICE_NR(device) ( ((device) & 3) | (((device) & 0x80 ) >> 5 )) -#define DEVICE_ON(device) floppy_on(DEVICE_NR(device)) +#define DEVICE_ON(device) #define DEVICE_OFF(device) floppy_off(DEVICE_NR(device)) #elif (MAJOR_NR == HD_MAJOR) diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 0e20a44f0b98..70032aaf287c 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -23,10 +23,12 @@ * drives attached to both, please mail me: Alain.Knaff@imag.fr */ /* #define HAVE_2_CONTROLLERS */ -/* Undefine the following if you have problems accessing ED disks, but don't - * have problems accessing them with the stock driver. If that is the case, - * please mail me: Alain.Knaff@imag.fr */ -/* #define FDC_FIFO_BUG */ + +/* Define the following if you don't like that your drives seek audibly + * after a disk change + */ +#define SILENT_DC_CLEAR + /* End of configuration */ @@ -98,6 +100,11 @@ * disk types. */ +/* + * 1994/8/8 -- Alain Knaff -- Switched to fdpatch driver: Support for bigger + * format bug fixes, but unfortunately some new bugs too... + */ + /* 1994/9/17 -- Koen Holtman -- added logging of physical floppy write * errors to allow safe writing by specialized programs. */ @@ -108,6 +115,7 @@ #define DEBUGT 2 +#include #include #include #include @@ -131,7 +139,7 @@ #define MAJOR_NR FLOPPY_MAJOR #include "blk.h" -static unsigned int changed_floppies = 0, fake_change = 0; +static unsigned int changed_floppies = 0xff, fake_change = 0; static int initialising=1; @@ -159,6 +167,17 @@ static int initialising=1; #define UDRWE (&write_errors[drive]) #define UFDCS (&fdc_state[FDC(drive)]) +#define DPRINT(x) printk(DEVICE_NAME "%d: " x,current_drive); + +#define DPRINT1(x,x1) \ +printk(DEVICE_NAME "%d: " x,current_drive,(x1)); + +#define DPRINT2(x,x1,x2) \ +printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2)); + +#define DPRINT3(x,x1,x2,x3) \ +printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2),(x3)); + /* read/write */ #define COMMAND raw_cmd.cmd[0] #define DR_SELECT raw_cmd.cmd[1] @@ -295,12 +314,12 @@ static struct floppy_struct floppy_type[32] = { { 2988,18,2,83,0,0x25,0x00,0xDF,0x02,"h1494" }, /* 18 1.49MB 5.25" */ { 3486,21,2,83,0,0x25,0x00,0xDF,0x0C,"H1743" }, /* 19 1.74 MB 3.5" */ - { 1760,11,2,80,0,0x1C,0x09,0xCF,0x6C,"d880" }, /* 20 880KB 5.25" */ + { 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" */ - { 3840,24,2,80,0,0x1C,0x18,0xCF,0x6C,"H1920" }, /* 25 1.92MB 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" */ { 7680,48,2,80,0,0x25,0x63,0xCF,0x6C,"E3840" }, /* 28 3.84MB 3.5" */ @@ -345,6 +364,8 @@ static int probing = 0; static volatile int command_status = FD_COMMAND_NONE, fdc_busy = 0; static struct wait_queue *fdc_wait = NULL, *command_done = NULL; +#define NO_SIGNAL (!(current->signal & ~current->blocked) || !interruptible) +#define CALL(x) if( (x) == -EINTR) return -EINTR; /* Errors during formatting are counted here. */ static int format_errors; @@ -366,6 +387,7 @@ static struct format_descr format_req; * Note that you must not change the sizes below without updating head.S. */ extern char floppy_track_buffer[512*2*MAX_BUFFER_SECTORS]; +#define max_buffer_sectors MAX_BUFFER_SECTORS int *errors; typedef void (*done_f)(int); @@ -377,13 +399,14 @@ void (*error)(void); /* this is called to tally an error */ done_f done; /* this is called to say if the operation has succeeded/failed */ } *cont; -static void floppy_ready(void); +static void floppy_start(void); +static void redo_fd_request(void); static void recalibrate_floppy(void); static void seek_floppy(void); static void floppy_shutdown(void); -int floppy_grab_irq_and_dma(void); -void floppy_release_irq_and_dma(void); +static int floppy_grab_irq_and_dma(void); +static void floppy_release_irq_and_dma(void); /* * The "reset" variable should be tested whenever an interrupt is scheduled, @@ -411,10 +434,6 @@ static int buffer_drive = -1; static int buffer_min = -1; static int buffer_max = -1; -#ifdef FDC_FIFO_BUG -static int force=0; -#endif - /* fdc related variables, should end up in a struct */ static struct floppy_fdc_state fdc_state[N_FDC]; int fdc; /* current fdc */ @@ -455,31 +474,84 @@ static inline void debugt(char *message) * This part of the file contains the code talking directly to the hardware, * and also the main service loop (seek-configure-spinup-command) */ + +/* + * disk change. + * This routine is responsible for maintaining the changed_floppies flag, + * and the last_checked date. + * + * last_checked is the date of the last check which showed 'no disk change' + * changed_floppies is set under two conditions: + * 1. The floppy has been changed after some i/o to that floppy already + * took place. + * 2. No floppy disk is in the drive. + * + * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet. + * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on + * each seek. If a disk is present, the disk change line should also be + * cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk + * change line is set, this means either that no disk is in the drive, or + * that it has been removed since the last seek. + * + * This means that we really have a third possibility too: + * The floppy has been changed after the last seek. + */ + +static int disk_change(int drive) +{ + if(inb_p(FD_DIR) & 0x80){ + UDRS->flags |= FD_VERIFY; /* verify write protection */ + + if(UDRS->maxblock || /* disk change check */ + !(UDRS->flags & FD_DISK_NEWCHANGE)){/* disk presence check */ + /* mark it changed or absent */ + set_bit(drive,&changed_floppies); + + /* invalidate its geometry */ + if (UDRS->keep_data >= 0) { + if ((DP->flags & FTD_MSG) && + current_type[drive] != NULL) + DPRINT("Disk type is undefined after " + "disk change\n"); + current_type[drive] = NULL; + floppy_sizes[drive] = MAX_DISK_SIZE; + } + } + UDRS->flags |= FD_DISK_NEWCHANGE; + return 1; + } else { + UDRS->last_checked=jiffies; + UDRS->flags &= ~FD_DISK_NEWCHANGE; + return 0; + } +} + + static int set_dor(int fdc, char mask, char data) { register unsigned char drive, unit, newdor,olddor; + cli(); olddor = FDCS->dor; newdor = (olddor & mask) | data; if ( newdor != olddor ){ unit = olddor & 0x3; drive = REVDRIVE(fdc,unit); - if ( olddor & ( 0x10 << unit )){ - if ( inb_p( FD_DIR ) & 0x80 ) - UDRS->flags |= FD_VERIFY; - else - UDRS->last_checked=jiffies; - } + if ( olddor & ( 0x10 << unit )) + disk_change(drive); FDCS->dor = newdor; outb_p( newdor, FD_DOR); } + sti(); return olddor; } static void twaddle(void) { + cli(); outb_p(FDCS->dor & ~(0x10<dor, FD_DOR); + sti(); } /* reset all driver information about the current fdc. This is needed after @@ -516,34 +588,47 @@ static void set_fdc(int drive) FDCS->reset = 1; } +static int usage_count = 0; /* locks the driver */ -static void lock_fdc(int drive) +static int lock_fdc(int drive, int interruptible) { + + if(!usage_count){ + printk("trying to lock fdc while usage count=0\n"); + return -1; + } + floppy_grab_irq_and_dma(); cli(); - while (fdc_busy) sleep_on(&fdc_wait); + while (fdc_busy && NO_SIGNAL) + interruptible_sleep_on(&fdc_wait); + if(fdc_busy){ + sti(); + return -EINTR; + } fdc_busy = 1; sti(); command_status = FD_COMMAND_NONE; set_fdc(drive); + return 0; } +#define LOCK_FDC(drive,interruptible) \ +if(lock_fdc(drive,interruptible)) return -EINTR; + /* unlocks the driver */ -static inline int unlock_fdc(void) +static inline void unlock_fdc(void) { - if (current_drive < N_DRIVE) - floppy_off(current_drive); if (!fdc_busy) - printk(DEVICE_NAME ": FDC access conflict!\n"); + DPRINT("FDC access conflict!\n"); if ( DEVICE_INTR ) - printk(DEVICE_NAME - ":device interrupt still active at FDC release: %p!\n", - DEVICE_INTR); + DPRINT1("device interrupt still active at FDC release: %p!\n", + DEVICE_INTR); command_status = FD_COMMAND_NONE; timer_active &= ~(1 << FLOPPY_TIMER); fdc_busy = 0; + floppy_release_irq_and_dma(); wake_up(&fdc_wait); - return 0; } /* switches the motor off after a given timeout */ @@ -621,10 +706,10 @@ static struct timer_list fd_timer ={ NULL, NULL, 0, 0, 0 }; * transfer */ static void fd_watchdog(void) { - if ( inb_p( FD_DIR ) & 0x80 ){ - changed_floppies |= ( 1 << current_drive); + if ( disk_change(current_drive) ){ + DPRINT("disk removed during i/o\n"); floppy_shutdown(); - } else { + } else { del_timer(&fd_timer); fd_timer.function = (timeout_fn) fd_watchdog; fd_timer.expires = 10; @@ -666,7 +751,7 @@ static void setup_DMA(void) raw_cmd.length > 512 * CURRENT->nr_sectors) && (current_addr < floppy_track_buffer || current_addr + raw_cmd.length > - floppy_track_buffer + 1024 * MAX_BUFFER_SECTORS)){ + floppy_track_buffer + 1024 * max_buffer_sectors)){ printk("bad address. start=%p lg=%lx tb=%p\n", current_addr, raw_cmd.length, floppy_track_buffer); if ( CURRENT ){ @@ -714,16 +799,11 @@ static int output_byte(char byte) if (FDCS->reset) return -1; - for(counter = 0 ; counter < 10000 ; counter++) { + for(counter = 0 ; counter < 10000 && !FDCS->reset ; counter++) { status = inb_p(FD_STATUS) &(STATUS_READY|STATUS_DIR|STATUS_DMA); if (!(status & STATUS_READY)) continue; - if (status == STATUS_READY -#ifdef FDC_FIFO_BUG - || ((status == STATUS_READY|STATUS_DIR|STATUS_BUSY) &&force) -#endif - ) - { + if (status == STATUS_READY){ outb_p(byte,FD_DATA); return 0; } else @@ -731,18 +811,12 @@ static int output_byte(char byte) } FDCS->reset = 1; if ( !initialising ) - printk(DEVICE_NAME ": Unable to send byte to FDC %d (%x)\n", - fdc, status); + DPRINT2("Unable to send byte %x to FDC. Status=%x\n", + byte, status); return -1; } #define LAST_OUT(x) if(output_byte(x)){ reset_fdc();return;} -#ifdef FDC_FIFO_BUG -#define output_byte_force(x) force=1;output_byte(x);force=0; -#else -#define output_byte_force(x) output_byte(x); -#endif - /* gets the response from the fdc */ static int result(void) { @@ -750,7 +824,7 @@ static int result(void) if (FDCS->reset) return -1; - for (counter = 0 ; counter < 10000 ; counter++) { + for (counter = 0 ; counter < 10000 && !FDCS->reset ; counter++) { status = inb_p(FD_STATUS)& (STATUS_DIR|STATUS_READY|STATUS_BUSY|STATUS_DMA); if (!(status & STATUS_READY)) @@ -761,8 +835,7 @@ static int result(void) break; if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY)) { if (i >= MAX_REPLIES) { - printk(DEVICE_NAME - ": floppy_stat reply overrun\n"); + DPRINT("floppy_stat reply overrun\n"); break; } reply_buffer[i++] = inb_p(FD_DATA); @@ -770,14 +843,13 @@ static int result(void) } FDCS->reset = 1; if ( !initialising ) - printk(DEVICE_NAME ": Getstatus times out (%x) on fdc %d [%d]\n", - status, fdc,i); + DPRINT3("Getstatus times out (%x) on fdc %d [%d]\n", + status, fdc, i); return -1; } /* Set perpendicular mode as required, based on data rate, if supported. - * 82077 Untested! 1Mbps data rate only possible with 82077-1. - * TODO: increase MAX_BUFFER_SECTORS, add floppy_type entries. + * 82077 Now tested. 1Mbps data rate only possible with 82077-1. */ static inline void perpendicular_mode(void) { @@ -788,14 +860,13 @@ static inline void perpendicular_mode(void) if (floppy->rate & 0x40){ switch(raw_cmd.rate){ case 0: - perp_mode=/*2*/3; + perp_mode=2; break; case 3: perp_mode=3; break; default: - printk(DEVICE_NAME - ": Invalid data rate for perpendicular mode!\n"); + DPRINT("Invalid data rate for perpendicular mode!\n"); cont->done(0); FDCS->reset = 1; /* convenient way to return to * redo without to much hassle (deep @@ -809,11 +880,10 @@ static inline void perpendicular_mode(void) return; if (FDCS->version >= FDC_82077_ORIG && FDCS->has_fifo) { output_byte(FD_PERPENDICULAR); - output_byte_force(perp_mode); + output_byte(perp_mode); FDCS->perp_mode = perp_mode; } else if (perp_mode) { - printk(DEVICE_NAME - ": perpendicular mode not supported by this FDC.\n"); + DPRINT("perpendicular mode not supported by this FDC.\n"); } } /* perpendicular_mode */ @@ -853,15 +923,15 @@ static void fdc_specify(void) /* Turn on FIFO for 82077-class FDC (improves performance) */ /* TODO: lock this in via LOCK during initialization */ output_byte(FD_CONFIGURE); - output_byte_force(0); + output_byte(0); output_byte(0x1A); /* FIFO on, polling off, 10 byte threshold */ - output_byte_force(0); /* precompensation from track 0 upwards */ + output_byte(0); /* precompensation from track 0 upwards */ if ( FDCS->reset ){ FDCS->has_fifo=0; return; } FDCS->need_configure = 0; - /*printk(DEVICE_NAME ": FIFO enabled\n");*/ + /*DPRINT("FIFO enabled\n");*/ } switch (raw_cmd.rate & 0x03) { @@ -902,8 +972,7 @@ static void fdc_specify(void) hut = hut_max_code; spec1 = (srt << 4) | hut; -#define fd_disable_dma 0 - spec2 = (hlt << 1) | fd_disable_dma; + spec2 = (hlt << 1); /* If these parameters did not change, just return with success */ if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) { @@ -955,7 +1024,7 @@ static int interpret_errors(void) char bad; if (inr!=7) { - printk(DEVICE_NAME ": -- FDC reply error"); + DPRINT("-- FDC reply error"); FDCS->reset = 1; return 1; } @@ -965,7 +1034,7 @@ static int interpret_errors(void) case 1: /* error occured during command execution */ bad = 1; if (ST1 & ST1_WP) { - printk(DEVICE_NAME ": Drive %d is write protected\n", current_drive); + DPRINT("Drive is write protected\n"); DRS->flags &= ~FD_DISK_WRITABLE; cont->done(0); bad = 2; @@ -973,11 +1042,10 @@ static int interpret_errors(void) DRS->flags |= FD_NEED_TWADDLE; } else if (ST1 & ST1_OR) { if (DP->flags & FTD_MSG ) - printk(DEVICE_NAME ": Over/Underrun - retrying\n"); - /* could continue from where we stopped, but ... */ + DPRINT("Over/Underrun - retrying\n"); bad = 0; }else if(*errors >= DP->max_errors.reporting){ - printk(DEVICE_NAME " %d: ", ST0 & ST0_DS); + DPRINT(""); if (ST0 & ST0_ECE) { printk("Recalibrate failed!"); } else if (ST2 & ST2_CRC) { @@ -1008,11 +1076,11 @@ static int interpret_errors(void) DRS->track = NEED_2_RECAL; return bad; case 2: /* invalid command given */ - printk(DEVICE_NAME ": Invalid FDC command given!\n"); + DPRINT("Invalid FDC command given!\n"); cont->done(0); return 2; case 3: - printk(DEVICE_NAME ": Abnormal termination caused by polling\n"); + DPRINT("Abnormal termination caused by polling\n"); cont->error(); return 2; default: /* (0) Normal command termination */ @@ -1034,7 +1102,7 @@ static void setup_rw_floppy(void) if ( flags & ( FD_RAW_READ | FD_RAW_WRITE)) flags |= FD_RAW_INTR; - if (flags & FD_RAW_SPIN){ + if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)){ ready_date = DRS->spinup_date + DP->spinup; /* If spinup will take a long time, rerun scandrives * again just before spinup completion. Beware that @@ -1042,7 +1110,7 @@ static void setup_rw_floppy(void) */ if ( ready_date > jiffies + DP->select_delay){ ready_date -= DP->select_delay; - function = (timeout_fn) floppy_on; + function = (timeout_fn) floppy_start; } else function = (timeout_fn) setup_rw_floppy; @@ -1052,11 +1120,8 @@ static void setup_rw_floppy(void) } dflags = DRS->flags; - if ( (flags & FD_RAW_READ) || (flags & FD_RAW_WRITE)){ - if ( flags & FD_RAW_USER_SUPPLIED ) - buffer_track = -1; + if ( (flags & FD_RAW_READ) || (flags & FD_RAW_WRITE)) setup_DMA(); - } if ( flags & FD_RAW_INTR ) SET_INTR(main_command_interrupt); @@ -1080,6 +1145,10 @@ static void setup_rw_floppy(void) fd_watchdog(); } +#ifdef SILENT_DC_CLEAR +static int blind_seek; +#endif + /* * This is the routine called after every seek (or recalibrate) interrupt * from the floppy controller. @@ -1088,32 +1157,58 @@ static void seek_interrupt(void) { #ifdef DEBUGT debugt("seek interrupt:"); +#endif +#ifdef SILENT_DC_CLEAR + set_dor(fdc, ~0, (0x10 << UNIT(current_drive))); #endif if (inr != 2 || (ST0 & 0xF8) != 0x20 ) { - printk(DEVICE_NAME ": seek failed\n"); + DPRINT("seek failed\n"); DRS->track = NEED_2_RECAL; cont->error(); cont->redo(); return; } - if ( DRS->track >= 0 && DRS->track != ST1 ) - DRS->flags &= ~FD_DISK_NEWCHANGE; + if (DRS->track >= 0 && DRS->track != ST1 +#ifdef SILENT_DC_CLEAR + && !blind_seek +#endif + ) + DRS->flags &= ~FD_DISK_NEWCHANGE; /* effective seek */ DRS->track = ST1; seek_floppy(); } +static void check_wp(void) +{ + if (DRS->flags & FD_VERIFY) { + /* check write protection */ + output_byte( FD_GETSTATUS ); + output_byte( UNIT(current_drive) ); + if ( result() != 1 ){ + FDCS->reset = 1; + return; + } + DRS->flags &= ~(FD_VERIFY | FD_DISK_WRITABLE | FD_NEED_TWADDLE); + + if (!( ST3 & 0x40)) + DRS->flags |= FD_DISK_WRITABLE; + } +} + static void seek_floppy(void) { int track; +#ifdef SILENT_DC_CLEAR + blind_seek=0; +#endif + disk_change(current_drive); if ((raw_cmd.flags & FD_RAW_NEED_DISK) && - !(DRS->flags & FD_DISK_NEWCHANGE ) && - (inb_p(FD_DIR) & 0x80)){ + test_bit(current_drive,&changed_floppies)){ /* the media changed flag should be cleared after the seek. * If it isn't, this means that there is really no disk in * the drive. */ - changed_floppies |= ( 1 << current_drive); cont->done(0); cont->redo(); return; @@ -1122,26 +1217,38 @@ static void seek_floppy(void) recalibrate_floppy(); return; } else if ((DRS->flags & FD_DISK_NEWCHANGE) && + (raw_cmd.flags & FD_RAW_NEED_DISK) && (DRS->track <= NO_TRACK || DRS->track == raw_cmd.track)) { /* we seek to clear the media-changed condition. Does anybody * know a more elegant way, which works on all drives? */ if ( raw_cmd.track ) track = raw_cmd.track - 1; - else + else { +#ifdef SILENT_DC_CLEAR + set_dor(fdc, ~ (0x10 << UNIT(current_drive)), 0); + blind_seek = 1; +#endif track = 1; - } else if (raw_cmd.track != DRS->track) - track = raw_cmd.track; - else { - setup_rw_floppy(); - return; + } + } else { + check_wp(); + if (raw_cmd.track != DRS->track) + track = raw_cmd.track; + else { + setup_rw_floppy(); + return; + } } +#ifndef SILENT_DC_CLEAR if ( !track && DRS->track >= 0 && DRS->track < 80 ){ DRS->flags &= ~FD_DISK_NEWCHANGE; /* if we go to track 0 anyways, we can just as well use * recalibrate */ recalibrate_floppy(); - } else { + } else +#endif + { SET_INTR(seek_interrupt); output_byte(FD_SEEK); output_byte(UNIT(current_drive)); @@ -1213,8 +1320,7 @@ static void unexpected_floppy_interrupt(void) int i; if ( initialising ) return; - printk(DEVICE_NAME ": unexpected interrupt\n"); - inr = result(); + DPRINT("unexpected interrupt\n"); if ( inr >= 0 ) for(i=0; ireset = 1; } -static void floppy_bh(void (*handler)(void)) -{ - inr = result(); - if ( inr == 0 ){ - do { - output_byte(FD_SENSEI); - inr = result(); - } while ( (ST0 & 0x83) != UNIT(current_drive) && inr == 2); - } - handler(); -} - struct tq_struct floppy_tq = -{ 0, 0, (void *) (void *) floppy_bh, 0 }; +{ 0, 0, (void *) (void *) unexpected_floppy_interrupt, 0 }; /* interrupt handler */ static void floppy_interrupt(int unused) @@ -1255,12 +1349,19 @@ static void floppy_interrupt(int unused) printk("floppy interrupt on bizarre fdc\n"); return; } - if (!handler) + inr = result(); + if (!handler){ unexpected_floppy_interrupt(); - else { - floppy_tq.data = (void *) handler; - queue_task_irq(&floppy_tq, &tq_timer); + return; + } + if ( inr == 0 ){ + do { + output_byte(FD_SENSEI); + inr = result(); + } while ( (ST0 & 0x83) != UNIT(current_drive) && inr == 2); } + floppy_tq.routine = (void *)(void *) handler; + queue_task_irq(&floppy_tq, &tq_timer); } static void recalibrate_floppy(void) @@ -1310,86 +1411,88 @@ static void empty(void) { } +void show_floppy(void) +{ + int i; + + printk("\n"); + printk("floppy driver state\n"); + printk("-------------------\n"); + for(i=0; ireset = 1; cont->done(0); cont->redo(); /* this will recall reset when needed */ } /* start motor, check media-changed condition and write protection */ -static int start_motor(void) +static void start_motor(void) { - int cnt; - int dir; + int mask, data; + mask = 0xfc; + data = UNIT(current_drive); if ( (FDCS->dor & 0x03) != UNIT(current_drive) ) /* notes select time if floppy is not yet selected */ DRS->select_date = jiffies; - if ( ! ( FDCS->dor & ( 0x10 << UNIT(current_drive) ) )){ - set_debugt(); - /* no read since this drive is running */ - DRS->first_read_date = 0; - /* note motor start time if motor is not yet running */ - DRS->spinup_date = jiffies; - } + if (!(raw_cmd.flags & FD_RAW_NO_MOTOR)){ + if(!(FDCS->dor & ( 0x10 << UNIT(current_drive) ) )){ + set_debugt(); + /* no read since this drive is running */ + DRS->first_read_date = 0; + /* note motor start time if motor is not yet running */ + DRS->spinup_date = jiffies; + data |= (0x10 << UNIT(current_drive)); + } + } else + if (FDCS->dor & ( 0x10 << UNIT(current_drive) ) ) + mask &= ~(0x10 << UNIT(current_drive)); /* starts motor and selects floppy */ del_timer(motor_off_timer + current_drive); - set_dor( fdc, 0xfc, - ( 0x10 << UNIT(current_drive) ) | UNIT(current_drive) ); - - dir = inb_p( FD_DIR) & 0x80; - if ( ! (dir & 0x80) ) - DRS->last_checked =jiffies; - if ( dir || ( DRS->flags & FD_VERIFY )) { - DRS->flags &= FD_DRIVE_PRESENT | FD_DISK_NEWCHANGE; - DRS->flags |= FD_DISK_WRITABLE; + set_dor( fdc, mask, data); + if( raw_cmd.flags & FD_RAW_NO_MOTOR) + return; - /* check write protection */ - output_byte( FD_GETSTATUS ); - output_byte( UNIT(current_drive) ); - if ( (cnt=result()) != 1 ){ - changed_floppies |= 1 << current_drive; - FDCS->reset = 1; - DRS->flags |= FD_VERIFY; - return -1; - } - if ( ( ST3 & 0x60 ) == 0x60 ) - DRS->flags &= ~FD_DISK_WRITABLE; - - if ( ! ( DRS->flags & FD_DISK_NEWCHANGE) ){ - /* the following code is only executed the first time - * a particular disk change has been detected */ - changed_floppies |= 1 << current_drive; - if (DRS->keep_data >= 0) { - if ((DP->flags & FTD_MSG) && - current_type[current_drive] != NULL) - printk(DEVICE_NAME - ": Disk type is undefined after " - "disk change in fd%d\n", - current_drive); - current_type[current_drive] = NULL; - floppy_sizes[current_drive] = MAX_DISK_SIZE; - } - if ( ST3 & 0x10 ) - DRS->track = 0; - } - } - if ( dir ) /* check if media changed is still on */ - DRS->flags |= FD_DISK_NEWCHANGE; - else { - DRS->flags &= ~FD_DISK_NEWCHANGE; - DRS->last_checked =jiffies; - } + if(disk_change(current_drive)) + twaddle(); /* this clears the dcl on certain drive/controller + * combinations */ - return DRS->flags; + return; } static void floppy_ready(void) @@ -1411,7 +1514,7 @@ static void floppy_ready(void) setup_rw_floppy(); } -static void floppy_on(unsigned int drive) +static void floppy_start(void) { timer_table[FLOPPY_TIMER].expires = jiffies + DP->timeout; timer_active |= 1 << FLOPPY_TIMER; @@ -1422,7 +1525,7 @@ static void floppy_on(unsigned int drive) /* * ======================================================================== * here ends the bottom half. Exported routines are: - * floppy_on, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc, + * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc, * start_motor, reset_fdc, reset_fdc_info, interpret_errors. * Initialisation also uses output_byte, result, set_dor, floppy_interrupt * and set_dor. @@ -1448,15 +1551,30 @@ static struct cont_t wakeup_cont={ (done_f)empty }; -static int wait_til_done(void) +static int wait_til_done( void (*handler)(void ), int interruptible ) { int ret; - while(command_status < 2) + floppy_tq.routine = (void *)(void *) handler; + queue_task(&floppy_tq, &tq_timer); + + cli(); + while(command_status < 2 && NO_SIGNAL) if (current->pid) - sleep_on( & command_done ); - else + interruptible_sleep_on(&command_done); + else { + sti(); run_task_queue(&tq_timer); + cli(); + } + if(command_status < 2){ + sti(); + floppy_shutdown(); + redo_fd_request(); + return -EINTR; + } + sti(); + if ( FDCS->reset ) command_status = FD_COMMAND_ERROR; if ( command_status == FD_COMMAND_OKAY ) @@ -1627,7 +1745,7 @@ static void redo_format(void) raw_cmd.track = format_req.track << floppy->stretch; buffer_track = -1; setup_format_params(); - floppy_on(current_drive); + floppy_start(); #ifdef DEBUGT debugt("queue format request"); #endif @@ -1643,21 +1761,20 @@ static int do_format(int device, struct format_descr *tmp_format_req) { int okay; - lock_fdc(DRIVE(device)); + LOCK_FDC(DRIVE(device),1); set_floppy(device); if (!floppy || tmp_format_req->track >= floppy->track || tmp_format_req->head >= floppy->head){ - unlock_fdc(); + redo_fd_request(); return -EINVAL; } format_req = *tmp_format_req; format_errors = 0; cont = &format_cont; errors = &format_errors; - redo_format(); - okay=wait_til_done(); - unlock_fdc(); + CALL(okay=wait_til_done(redo_format,1)); + redo_fd_request(); return okay; } @@ -1676,8 +1793,7 @@ static void request_done(int uptodate) timer_active &= ~(1 << FLOPPY_TIMER); if (!CURRENT){ - printk(DEVICE_NAME - ": request list destroyed in floppy request done\n"); + DPRINT("request list destroyed in floppy request done\n"); return; } if (uptodate){ @@ -1707,7 +1823,7 @@ static void request_done(int uptodate) } if ( current_count_sectors && ! CURRENT ) - printk(DEVICE_NAME "request list destroyed in floppy request done\n"); + DPRINT("request list destroyed in floppy request done\n"); } else { if(CURRENT->cmd == WRITE) { @@ -1727,11 +1843,7 @@ static void request_done(int uptodate) /* Interrupt handler evaluating the result of the r/w operation */ static void rw_interrupt(void) { -#if 0 - int i; -#endif int nr_sectors, ssize; - char bad; if ( ! DRS->first_read_date ) DRS->first_read_date = jiffies; @@ -1746,8 +1858,8 @@ static void rw_interrupt(void) if ( nr_sectors > current_count_sectors + ssize - (current_count_sectors + sector_t) % ssize + sector_t % ssize){ - printk(DEVICE_NAME ": long rw: %x instead of %lx\n", - nr_sectors, current_count_sectors); + DPRINT2("long rw: %x instead of %lx\n", + nr_sectors, current_count_sectors); printk("rs=%d s=%d\n", R_SECTOR, SECTOR); printk("rh=%d h=%d\n", R_HEAD, HEAD); printk("rt=%d t=%d\n", R_TRACK, TRACK); @@ -1757,23 +1869,8 @@ static void rw_interrupt(void) #endif if ( nr_sectors < 0 ) nr_sectors = 0; - if ( nr_sectors < current_count_sectors ){ -#if 0 - printk(DEVICE_NAME ": short read got %d instead of %ld\n", - nr_sectors, current_count_sectors); -#endif -#if 0 - printk("command: "); - for(i=0; ierror(); cont->redo(); return; } @@ -1806,9 +1896,8 @@ static void rw_interrupt(void) if (probing) { if (DP->flags & FTD_MSG) - printk(DEVICE_NAME - ": Auto-detected floppy type %s in fd%d\n", - floppy->name,current_drive); + DPRINT2("Auto-detected floppy type %s in fd%d\n", + floppy->name,current_drive); current_type[current_drive] = floppy; floppy_sizes[DRIVE(current_drive) + (FDC(current_drive) << 7)] = floppy->size >> 1; @@ -1840,7 +1929,7 @@ static int buffer_chain_size(void) #ifdef SANITY if ( !bh ){ - printk(DEVICE_NAME ": null request in buffer_chain_size\n"); + DPRINT("null request in buffer_chain_size\n"); return size >> 9; } #endif @@ -1893,7 +1982,7 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2) #ifdef SANITY if ((remaining >> 9) > CURRENT->nr_sectors && CT(COMMAND) == FD_WRITE ){ - printk(DEVICE_NAME ": in copy buffer\n"); + DPRINT("in copy buffer\n"); printk("current_count_sectors=%ld\n", current_count_sectors); printk("remaining=%d\n", remaining >> 9); printk("CURRENT->nr_sectors=%ld\n",CURRENT->nr_sectors); @@ -1918,16 +2007,14 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2) size = remaining; #ifdef SANITY if (!bh){ - printk(DEVICE_NAME - ": bh=null in copy buffer before copy\n"); + DPRINT("bh=null in copy buffer before copy\n"); break; } if (dma_buffer + size > - floppy_track_buffer + ( 2 * MAX_BUFFER_SECTORS << 9 ) || + floppy_track_buffer + (max_buffer_sectors << 10) || dma_buffer < floppy_track_buffer ){ - printk(DEVICE_NAME - ": buffer overrun in copy buffer %d\n", - (floppy_track_buffer - dma_buffer) >>9); + DPRINT1("buffer overrun in copy buffer %d\n", + (floppy_track_buffer - dma_buffer) >>9); printk("sector_t=%d buffer_min=%d\n", sector_t, buffer_min); printk("current_count_sectors=%ld\n", @@ -1939,7 +2026,7 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2) break; } if ( ((int)buffer) % 512 ) - printk(DEVICE_NAME ": %p buffer not aligned\n", buffer); + DPRINT1("%p buffer not aligned\n", buffer); #endif if ( CT(COMMAND) == FD_READ ) memcpy( buffer, dma_buffer, size); @@ -1953,8 +2040,7 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2) bh = bh->b_reqnext; #ifdef SANITY if ( !bh){ - printk(DEVICE_NAME - ": bh=null in copy buffer after copy\n"); + DPRINT("bh=null in copy buffer after copy\n"); break; } #endif @@ -1965,8 +2051,7 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2) if ( remaining ){ if ( remaining > 0 ) max_sector -= remaining >> 9; - printk(DEVICE_NAME - ": weirdness: remaining %d\n", remaining>>9); + DPRINT1("weirdness: remaining %d\n", remaining>>9); } #endif } @@ -1998,8 +2083,7 @@ static int make_raw_rw_request(void) raw_cmd.flags |= FD_RAW_WRITE; COMMAND = FM_MODE(floppy,FD_WRITE); } else { - printk(DEVICE_NAME - ": make_raw_rw_request: unknown command\n"); + DPRINT("make_raw_rw_request: unknown command\n"); return 0; } @@ -2081,7 +2165,7 @@ static int make_raw_rw_request(void) } else if ((long)CURRENT->buffer <= LAST_DMA_ADDR ) { int direct, indirect; - indirect= transfer_size(ssize,max_sector,MAX_BUFFER_SECTORS*2) - + indirect= transfer_size(ssize,max_sector,max_buffer_sectors*2) - sector_t; max_size = buffer_chain_size(); @@ -2121,8 +2205,8 @@ static int make_raw_rw_request(void) sector_t < buffer_min || ((CT(COMMAND) == FD_READ || (aligned_sector_t == sector_t && CURRENT->nr_sectors >= ssize ))&& - max_sector > 2 * MAX_BUFFER_SECTORS + buffer_min && - max_size + sector_t > 2 * MAX_BUFFER_SECTORS + buffer_min) + max_sector > 2 * max_buffer_sectors + buffer_min && + max_size + sector_t > 2 * max_buffer_sectors + buffer_min) /* not enough space */ ){ buffer_track = -1; buffer_drive = current_drive; @@ -2137,15 +2221,14 @@ static int make_raw_rw_request(void) * (buffer will be overwritten) */ #ifdef SANITY if (sector_t != aligned_sector_t && buffer_track == -1 ) - printk(DEVICE_NAME - ": internal error offset !=0 on write\n"); + DPRINT("internal error offset !=0 on write\n"); #endif buffer_track = raw_cmd.track; buffer_drive = current_drive; - copy_buffer(ssize, max_sector, 2*MAX_BUFFER_SECTORS+buffer_min); + copy_buffer(ssize, max_sector, 2*max_buffer_sectors+buffer_min); } else transfer_size(ssize, max_sector, - 2*MAX_BUFFER_SECTORS+buffer_min-aligned_sector_t); + 2*max_buffer_sectors+buffer_min-aligned_sector_t); /* round up current_count_sectors to get dma xfer size */ raw_cmd.length = sector_t+current_count_sectors-aligned_sector_t; @@ -2159,8 +2242,8 @@ static int make_raw_rw_request(void) aligned_sector_t < buffer_min )) || raw_cmd.length % ( 128 << SIZECODE ) || raw_cmd.length <= 0 || current_count_sectors <= 0){ - printk(DEVICE_NAME ": fractionary current count b=%lx s=%lx\n", - raw_cmd.length, current_count_sectors); + DPRINT2("fractionary current count b=%lx s=%lx\n", + raw_cmd.length, current_count_sectors); if ( current_addr != CURRENT->buffer ) printk("addr=%d, length=%ld\n", (current_addr - floppy_track_buffer ) >> 9, @@ -2182,9 +2265,8 @@ static int make_raw_rw_request(void) current_count_sectors < 0 || raw_cmd.length < 0 || current_addr + raw_cmd.length > - floppy_track_buffer + ( 2 * MAX_BUFFER_SECTORS << 9 )){ - printk(DEVICE_NAME - ": buffer overrun in schedule dma\n"); + floppy_track_buffer + (max_buffer_sectors << 10)){ + DPRINT("buffer overrun in schedule dma\n"); printk("sector_t=%d buffer_min=%d current_count=%ld\n", sector_t, buffer_min, raw_cmd.length >> 9 ); @@ -2198,10 +2280,10 @@ static int make_raw_rw_request(void) } } else if (raw_cmd.length > CURRENT->nr_sectors << 9 || current_count_sectors > CURRENT->nr_sectors){ - printk(DEVICE_NAME ": buffer overrun in direct transfer\n"); + DPRINT("buffer overrun in direct transfer\n"); return 0; } else if ( raw_cmd.length < current_count_sectors << 9 ){ - printk(DEVICE_NAME ": more sectors than bytes\n"); + DPRINT("more sectors than bytes\n"); printk("bytes=%ld\n", raw_cmd.length >> 9 ); printk("sectors=%ld\n", current_count_sectors); } @@ -2209,15 +2291,24 @@ static int make_raw_rw_request(void) return 2; } +static struct cont_t rw_cont={ + rw_interrupt, + redo_fd_request, + bad_flp_intr, + request_done }; + static void redo_fd_request(void) { #define REPEAT {request_done(0); continue; } int device; int tmp; + if (current_drive < N_DRIVE) + floppy_off(current_drive); + if (CURRENT && CURRENT->dev < 0) return; - - /* hooray, the goto is gone! */ + + cont = &rw_cont; while(1){ if (!CURRENT) { CLEAR_INTR; @@ -2229,13 +2320,16 @@ static void redo_fd_request(void) if (CURRENT->bh && !CURRENT->bh->b_lock) panic(DEVICE_NAME ": block not locked"); - device = MINOR(CURRENT->dev); + device = CURRENT->dev; set_fdc( DRIVE(device)); - CHECK_RESET; + + timer_table[FLOPPY_TIMER].expires = jiffies + DP->timeout; + timer_active |= 1 << FLOPPY_TIMER; + raw_cmd.flags=0; start_motor(); - if (( changed_floppies | fake_change) & ( 1 << DRIVE(device))){ - printk(DEVICE_NAME - ": disk absent or changed during operation\n"); + if(test_bit( DRIVE(device), &fake_change) || + test_bit( DRIVE(device), &changed_floppies)){ + DPRINT("disk absent or changed during operation\n"); REPEAT; } set_floppy(device); @@ -2243,8 +2337,7 @@ static void redo_fd_request(void) if (!probing){ DRS->probed_format = 0; if ( next_valid_format() ){ - printk(DEVICE_NAME - ": no autodetectable formats\n"); + DPRINT("no autodetectable formats\n"); floppy = NULL; REPEAT; } @@ -2262,8 +2355,8 @@ static void redo_fd_request(void) if ( DRS->flags & FD_NEED_TWADDLE ) twaddle(); - - floppy_on(current_drive); + floppy_tq.routine = (void *)(void *) floppy_start; + queue_task(&floppy_tq, &tq_timer); #ifdef DEBUGT debugt("queue fd request"); #endif @@ -2272,18 +2365,15 @@ static void redo_fd_request(void) #undef REPEAT } -static struct cont_t rw_cont={ - rw_interrupt, - redo_fd_request, - bad_flp_intr, - request_done }; - void do_fd_request(void) { - if ( fdc_busy) - printk("do fd request\n"); - lock_fdc(-1); - cont = &rw_cont; + if (fdc_busy) + /* fdc busy, this new request will be treated when the + current one is done */ + return; + /* fdc_busy cannot be set by an interrupt or a bh */ + floppy_grab_irq_and_dma(); + fdc_busy=1; redo_fd_request(); } @@ -2303,12 +2393,12 @@ static struct cont_t reset_cont={ generic_failure, generic_done }; -static int user_reset_fdc(int drive, int arg) +static int user_reset_fdc(int drive, int arg, int interruptible) { int result; result=0; - lock_fdc(drive); + LOCK_FDC(drive,interruptible); switch(arg){ case FD_RESET_ALWAYS: FDCS->reset=1; @@ -2322,12 +2412,11 @@ static int user_reset_fdc(int drive, int arg) cont = &reset_cont; timer_table[FLOPPY_TIMER].expires = jiffies + 5; timer_active |= 1 << FLOPPY_TIMER; - reset_fdc(); - result=wait_til_done(); + CALL(result=wait_til_done(reset_fdc,interruptible)); } if ( UDRS->track == PROVEN_ABSENT ) UDRS->track = NEED_2_RECAL; - unlock_fdc(); + redo_fd_request(); return result; } @@ -2345,16 +2434,10 @@ static int fd_copyout(void *param, volatile void *address, int size) memcpy_tofs(param,(void *) address, size); return 0; } + #define COPYOUT(x) (fd_copyout( (void *)param, &(x), sizeof(x))) #define COPYIN(x) (memcpy_fromfs( &(x), (void *) param, sizeof(x)),0) -static void poll_drive(int drive) -{ - lock_fdc(drive); - start_motor(); - unlock_fdc(); -} - static char *drive_name(int type, int drive ) { struct floppy_struct *floppy; @@ -2390,10 +2473,14 @@ static int raw_cmd_ioctl(int drive, void *param) if ( FDC(i) != fdc) continue; if ( i == drive ){ - if ( drive_state[i].fd_ref > 1 ) - return -EBUSY; - } else if ( drive_state[i].fd_ref ) - return -EBUSY; + if ( drive_state[i].fd_ref > 1 ){ + FDCS->rawcmd = 2; + break; + } + } else if ( drive_state[i].fd_ref ){ + FDCS->rawcmd = 2; + break; + } } if(FDCS->reset) @@ -2402,23 +2489,27 @@ static int raw_cmd_ioctl(int drive, void *param) COPYIN(raw_cmd); raw_cmd.rate &= 0x03; count = raw_cmd.length; - if ((raw_cmd.flags & (FD_RAW_WRITE | FD_RAW_READ)) && - count > MAX_BUFFER_SECTORS * 512 * 2 ) - return -ENOMEM; - + if (raw_cmd.flags & (FD_RAW_WRITE | FD_RAW_READ)){ + if(count > max_buffer_sectors * 1024 ) + return -ENOMEM; + buffer_track = -1; + } if ( raw_cmd.flags & FD_RAW_WRITE ){ i = verify_area(VERIFY_READ, raw_cmd.data, count ); if (i) return i; - buffer_track = -1; memcpy_fromfs(floppy_track_buffer, raw_cmd.data, count); } current_addr = floppy_track_buffer; - raw_cmd.flags |= FD_RAW_USER_SUPPLIED; cont = &raw_cmd_cont; - floppy_on(current_drive); - ret=wait_til_done(); + CALL(ret=wait_til_done(floppy_start,1)); + if( inb_p(FD_DIR) & 0x80 ) + raw_cmd.flags |= FD_RAW_DISK_CHANGE; + else + raw_cmd.flags &= ~FD_RAW_DISK_CHANGE; + if(raw_cmd.flags & FD_RAW_NO_MOTOR_AFTER) + motor_off_callback(drive); if ( !ret && !FDCS->reset ){ raw_cmd.reply_count = inr; @@ -2437,16 +2528,16 @@ static int raw_cmd_ioctl(int drive, void *param) if (i) return i; } - + return COPYOUT(raw_cmd); } static int invalidate_drive(int rdev) { /* invalidate the buffer track to force a reread */ - fake_change |= 1 << DRIVE(rdev); + set_bit( DRIVE(rdev), &fake_change); + redo_fd_request(); check_disk_change(rdev); - unlock_fdc(); return 0; } @@ -2462,12 +2553,12 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, struct floppy_struct *this_floppy; char *name; - device = MINOR(inode->i_rdev); + device = inode->i_rdev; switch (cmd) { RO_IOCTLS(device,param); } - type = TYPE(MINOR(device)); - drive = DRIVE(MINOR(device)); + type = TYPE(device); + drive = DRIVE(device); switch (cmd) { case FDGETDRVTYP: i=verify_area(VERIFY_WRITE,(void *) param,16); @@ -2491,7 +2582,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, return -ENODEV; return COPYOUT(this_floppy[0]); case FDPOLLDRVSTAT: - poll_drive(drive); + check_disk_change(device); /* fall through */ case FDGETDRVSTAT: return COPYOUT(*UDRS); @@ -2516,10 +2607,10 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, case FDRAWCMD: if (type) return -EINVAL; - lock_fdc(drive); + LOCK_FDC(drive,1); set_floppy(device); - i = raw_cmd_ioctl(drive, (void *) param); - unlock_fdc(); + CALL(i = raw_cmd_ioctl(drive, (void *) param)); + redo_fd_request(); return i; case FDFMTTRK: if (UDRS->fd_ref != 1) @@ -2533,14 +2624,14 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, case FDFMTBEG: return 0; case FDCLRPRM: - lock_fdc(drive); + LOCK_FDC(drive,1); current_type[drive] = NULL; floppy_sizes[drive] = 2; UDRS->keep_data = 0; return invalidate_drive(device); case FDFMTEND: case FDFLUSH: - lock_fdc(drive); + LOCK_FDC(drive,1); return invalidate_drive(device); case FDSETPRM: case FDDEFPRM: @@ -2555,12 +2646,11 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, if ( type){ if ( !suser() ) return -EPERM; - lock_fdc(-1); + LOCK_FDC(-1,1); for ( cnt = 0; cnt < N_DRIVE; cnt++){ if (TYPE(drive_state[cnt].fd_device) == type && - drive_state[cnt].fd_ref){ - fake_change |= 1 << cnt; - } + drive_state[cnt].fd_ref) + set_bit(drive, &fake_change); } floppy_type[type] = newparams; floppy_type[type].name="user format"; @@ -2572,7 +2662,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, floppy_sizes[cnt+0x80]= #endif floppy_type[type].size>>1; - unlock_fdc(); + redo_fd_request(); for ( cnt = 0; cnt < N_DRIVE; cnt++){ if (TYPE(drive_state[cnt].fd_device) == type && drive_state[cnt].fd_ref) @@ -2582,11 +2672,13 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, return 0; } - lock_fdc(drive); - if ( cmd != FDDEFPRM ) + LOCK_FDC(drive,1); + if ( cmd != FDDEFPRM ){ /* notice a disk change immediately, else * we loose our settings immediately*/ + raw_cmd.flags = 0; start_motor(); + } user_params[drive] = newparams; if (buffer_drive == drive && buffer_max > user_params[drive].sect) @@ -2605,11 +2697,12 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, if (DRS->maxblock > user_params[drive].sect || DRS->maxtrack ) - return invalidate_drive(device); + invalidate_drive(device); else - return unlock_fdc(); + redo_fd_request(); + return 0; case FDRESET: - return user_reset_fdc( drive, (int)param); + return user_reset_fdc( drive, (int)param, 1); case FDMSGON: UDP->flags |= FTD_MSG; return 0; @@ -2621,9 +2714,9 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, (unsigned short) (param & 0x0f); return 0; case FDTWADDLE: - lock_fdc(drive); + LOCK_FDC(drive,1); twaddle(); - unlock_fdc(); + redo_fd_request(); } if ( ! suser() ) return -EPERM; @@ -2674,21 +2767,9 @@ static void config_types(void) printk("\n"); } - -static void maybe_check_change(int device) -{ - register int drive; - - drive = DRIVE(device); - if (UDRS->last_checked + UDP->checkfreq < jiffies || - UDRS->flags & FD_VERIFY || - (( changed_floppies | fake_change ) & ( 1 << drive))) - check_disk_change(device); -} - int floppy_is_wp( int minor) { - maybe_check_change(minor + (MAJOR_NR << 8)); + check_disk_change(minor + (MAJOR_NR << 8)); return ! ( drive_state[ DRIVE(minor) ].flags & FD_DISK_WRITABLE ); } @@ -2697,10 +2778,10 @@ int floppy_is_wp( int minor) static int floppy_##op(struct inode * inode, struct file * filp, \ char * buf, int count) \ { \ - maybe_check_change(inode->i_rdev); \ + check_disk_change(inode->i_rdev); \ if ( drive_state[DRIVE(inode->i_rdev)].track == PROVEN_ABSENT ) \ return -ENXIO; \ - if ( changed_floppies & ( 1 << DRIVE(inode->i_rdev) )) \ + if ( test_bit(DRIVE(inode->i_rdev),&changed_floppies)) \ return -ENXIO; \ return block_##op(inode, filp, buf, count); \ } @@ -2708,21 +2789,21 @@ static int floppy_##op(struct inode * inode, struct file * filp, \ WRAPPER(read) WRAPPER(write) -static int exclusive = 0; static void floppy_release(struct inode * inode, struct file * filp) { - int drive= DRIVE(inode->i_rdev); + int drive; + + drive = DRIVE(inode->i_rdev); - if(filp->f_mode & 2) - fsync_dev(inode->i_rdev); - if ( UDRS->fd_ref < 0) + fsync_dev(inode->i_rdev); + + if (UDRS->fd_ref < 0) UDRS->fd_ref=0; else if (!UDRS->fd_ref--) { - printk(DEVICE_NAME ": floppy_release with fd_ref == 0"); + DPRINT("floppy_release with fd_ref == 0"); UDRS->fd_ref = 0; } floppy_release_irq_and_dma(); - exclusive=0; } /* @@ -2733,17 +2814,14 @@ static void floppy_release(struct inode * inode, struct file * filp) #define RETERR(x) \ do{floppy_release(inode,filp); \ return -(x);}while(0) -static int usage_count = 0; + static int floppy_open(struct inode * inode, struct file * filp) { int drive; int old_dev; - if (exclusive) - return -EBUSY; - if (!filp) { - printk(DEVICE_NAME ": Weird, open called with filp=0\n"); + DPRINT("Weird, open called with filp=0\n"); return -EIO; } @@ -2751,11 +2829,6 @@ static int floppy_open(struct inode * inode, struct file * filp) if ( drive >= N_DRIVE || !( ALLOWED_DRIVE_MASK & ( 1 << drive)) ) return -ENXIO; - if (command_status == FD_COMMAND_DETECT && drive >= current_drive) { - lock_fdc(-1); - unlock_fdc(); - } - if (TYPE(inode->i_rdev) >= NUMBER(floppy_type)) return -ENXIO; @@ -2767,17 +2840,18 @@ static int floppy_open(struct inode * inode, struct file * filp) if (UDRS->fd_ref && old_dev != inode->i_rdev) return -EBUSY; - if (filp->f_flags & O_EXCL) { - if (usage_count) - return -EBUSY; - else - exclusive = 1; - } + if(UDRS->fd_ref == -1 || + (UDRS->fd_ref && (filp->f_flags & O_EXCL))) + return -EBUSY; if (floppy_grab_irq_and_dma()) return -EBUSY; - UDRS->fd_ref++; + if(filp->f_flags & O_EXCL) + UDRS->fd_ref = -1; + else + UDRS->fd_ref++; + UDRS->fd_device = inode->i_rdev; if (old_dev && old_dev != inode->i_rdev) { @@ -2799,15 +2873,16 @@ static int floppy_open(struct inode * inode, struct file * filp) if (filp->f_mode && UDRS->track == PROVEN_ABSENT ) RETERR(ENXIO); - if (user_reset_fdc(drive, FD_RESET_IF_NEEDED)) + if (user_reset_fdc(drive, FD_RESET_IF_NEEDED,0)) RETERR(EIO); if (filp->f_mode & 3) { + UDRS->last_checked = 0; check_disk_change(inode->i_rdev); - if (changed_floppies & ( 1 << drive )) + if (test_bit(drive,&changed_floppies)) RETERR(ENXIO); } - + if (filp->f_mode && UDRS->track == PROVEN_ABSENT ) RETERR(ENXIO); @@ -2817,50 +2892,41 @@ static int floppy_open(struct inode * inode, struct file * filp) #undef RETERR } -/* - * Acknowledge disk change - */ -static int ack_change(int drive) -{ - unsigned int mask = 1 << drive; - UDRS->maxblock = 0; - UDRS->maxtrack = 0; - if ( buffer_drive == drive ) - buffer_track = -1; - fake_change &= ~mask; - changed_floppies &= ~mask; - return 1; -} - /* * Check if the disk has been changed or if a change has been faked. */ static int check_floppy_change(dev_t dev) { int drive = DRIVE( dev ); - unsigned int mask = 1 << drive; if (MAJOR(dev) != MAJOR_NR) { - printk(DEVICE_NAME ": floppy_changed: not a floppy\n"); + DPRINT("floppy_changed: not a floppy\n"); return 0; } - if (fake_change & mask) - return ack_change(drive); + if(test_bit(drive, &changed_floppies)) + return 1; - if ((UDRS->flags & FD_VERIFY ) || (changed_floppies & mask) || - UDRS->last_checked + UDP->checkfreq < - jiffies){ - user_reset_fdc(drive, FD_RESET_IF_NEEDED); - poll_drive(drive); - if (changed_floppies & mask){ - UDRS->generation++; - return ack_change(drive); - } + if(UDRS->last_checked + UDP->checkfreq < jiffies){ + lock_fdc(drive,0); + start_motor(); + redo_fd_request(); } + + if(test_bit(drive, &changed_floppies)) + return 1; + if(test_bit(drive, &fake_change)) + return 1; return 0; } +static struct cont_t poll_cont={ + success_and_wakeup, + floppy_ready, + generic_failure, + generic_done }; + + /* revalidate the floppy disk, i.e. trigger format autodetection by reading * the bootblock (block 0). "Autodetection" is also needed to check wether * there is a disk in the drive at all... Thus we also do it for fixed @@ -2868,13 +2934,48 @@ static int check_floppy_change(dev_t dev) static int floppy_revalidate(dev_t dev) { struct buffer_head * bh; - - if (!(bh = getblk(dev,0,1024))) - return 1; - if ( bh && ! bh->b_uptodate) - ll_rw_block(READ, 1, &bh); - wait_on_buffer(bh); - brelse(bh); + int drive=DRIVE(dev); + int cf; + + cf = test_bit(drive, &changed_floppies); + if(cf || test_bit(drive, &fake_change)){ + lock_fdc(drive,0); + cf = test_bit(drive, &changed_floppies); + if(! (cf || test_bit(drive, &fake_change))){ + redo_fd_request(); /* already done by another thread */ + return 0; + } + UDRS->maxblock = 0; + UDRS->maxtrack = 0; + if ( buffer_drive == drive) + buffer_track = -1; + clear_bit(drive, &fake_change); + clear_bit(drive, &changed_floppies); + if(cf){ + UDRS->generation++; + if(!current_type[drive] && !TYPE(dev)){ + /* auto-sensing */ + if (!(bh = getblk(dev,0,1024))){ + redo_fd_request(); + return 1; + } + if ( bh && ! bh->b_uptodate) + ll_rw_block(READ, 1, &bh); + redo_fd_request(); + wait_on_buffer(bh); + brelse(bh); + return 0; + } else { + /* no auto-sense, just clear dcl */ + raw_cmd.flags=FD_RAW_NEED_SEEK|FD_RAW_NEED_DISK; + raw_cmd.track=0; + raw_cmd.cmd_count=0; + cont = &poll_cont; + wait_til_done(floppy_ready,0); + } + } + redo_fd_request(); + } return 0; } @@ -2946,6 +3047,8 @@ void floppy_init(void) { int i; + sti(); + if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) { printk("Unable to get major %d for floppy\n",MAJOR_NR); return; @@ -2979,7 +3082,7 @@ void floppy_init(void) /* initialise drive state */ for (i = 0; i < N_DRIVE ; i++) { current_drive = i; - DRS->flags = FD_VERIFY; + DRS->flags = FD_VERIFY | FD_DISK_NEWCHANGE; DRS->generation = 0; DRS->keep_data = 0; DRS->fd_ref = 0; @@ -2996,7 +3099,7 @@ void floppy_init(void) for (i = 0 ; i < N_FDC ; i++) { fdc = i; FDCS->rawcmd = 2; - if(user_reset_fdc(-1,FD_RESET_IF_NEEDED)) + if(user_reset_fdc(-1,FD_RESET_IF_NEEDED,0)) continue; /* Try to determine the floppy controller type */ FDCS->version = get_fdc_version(); @@ -3008,7 +3111,7 @@ void floppy_init(void) * to avoid interrupt garbage. */ FDCS->has_fifo = FDCS->version >= FDC_82077_ORIG; - user_reset_fdc(-1,FD_RESET_ALWAYS); + user_reset_fdc(-1,FD_RESET_ALWAYS,0); } fdc=0; current_drive = 0; @@ -3016,20 +3119,22 @@ void floppy_init(void) initialising=0; } -int floppy_grab_irq_and_dma(void) +static int floppy_grab_irq_and_dma(void) { - if (usage_count++) + cli(); + if (usage_count++){ + sti(); return 0; + } + sti(); if (request_irq(FLOPPY_IRQ, floppy_interrupt, SA_INTERRUPT, "floppy")) { - printk(DEVICE_NAME - ": Unable to grab IRQ%d for the floppy driver\n", - FLOPPY_IRQ); + DPRINT1("Unable to grab IRQ%d for the floppy driver\n", + FLOPPY_IRQ); return -1; } if (request_dma(FLOPPY_DMA,"floppy")) { - printk(DEVICE_NAME - ": Unable to grab DMA%d for the floppy driver\n", - FLOPPY_DMA); + DPRINT1("Unable to grab DMA%d for the floppy driver\n", + FLOPPY_DMA); free_irq(FLOPPY_IRQ); return -1; } @@ -3037,10 +3142,14 @@ int floppy_grab_irq_and_dma(void) return 0; } -void floppy_release_irq_and_dma(void) +static void floppy_release_irq_and_dma(void) { - if (--usage_count) + cli(); + if (--usage_count){ + sti(); return; + } + sti(); disable_dma(FLOPPY_DMA); free_dma(FLOPPY_DMA); disable_irq(FLOPPY_IRQ); diff --git a/drivers/block/hd.c b/drivers/block/hd.c index 08a77c0848d7..679c9cc67a1c 100644 --- a/drivers/block/hd.c +++ b/drivers/block/hd.c @@ -80,7 +80,7 @@ static int hd_error = 0; struct hd_i_struct { unsigned int head,sect,cyl,wpcom,lzone,ctl; }; -static struct hd_driveid *hd_ident_info[MAX_HD]; +static struct hd_driveid *hd_ident_info[MAX_HD] = {0, }; #ifdef HD_TYPE static struct hd_i_struct hd_info[] = { HD_TYPE }; @@ -275,16 +275,21 @@ static void identify_intr(void) { unsigned int dev = DEVICE_NR(CURRENT->dev); unsigned short stat = inb_p(HD_STATUS); - struct hd_driveid id; + struct hd_driveid *id = hd_ident_info[dev]; if (unmask_intr[dev]) sti(); - if (stat & (BUSY_STAT|ERR_STAT)) - printk (" hd%c: identity unknown\n", dev+'a'); - else { - insw(HD_DATA, (char *)&id, sizeof(id)/2); /* get ID bytes */ - max_mult[dev] = id.max_multsect; - if ((id.cur_valid&1) && id.cur_cyls && id.cur_heads && (id.cur_heads <= 16) && id.cur_sectors) { + if (stat & (BUSY_STAT|ERR_STAT)) { + printk (" hd%c: non-IDE device, CHS=%d%d%d\n", dev+'a', + hd_info[dev].cyl, hd_info[dev].head, hd_info[dev].sect); + if (id != NULL) { + hd_ident_info[dev] = NULL; + kfree_s (id, 512); + } + } else { + insw(HD_DATA, id, 256); /* get ID info */ + max_mult[dev] = id->max_multsect; + if ((id->field_valid&1) && id->cur_cyls && id->cur_heads && (id->cur_heads <= 16) && id->cur_sectors) { /* * Extract the physical drive geometry for our use. * Note that we purposely do *not* update the bios_info. @@ -292,31 +297,24 @@ static void identify_intr(void) * still have the same logical view as the BIOS does, * which keeps the partition table from being screwed. */ - hd_info[dev].cyl = id.cur_cyls; - hd_info[dev].head = id.cur_heads; - hd_info[dev].sect = id.cur_sectors; + hd_info[dev].cyl = id->cur_cyls; + hd_info[dev].head = id->cur_heads; + hd_info[dev].sect = id->cur_sectors; } - fixstring (id.serial_no, sizeof(id.serial_no)); - fixstring (id.fw_rev, sizeof(id.fw_rev)); - fixstring (id.model, sizeof(id.model)); + fixstring (id->serial_no, sizeof(id->serial_no)); + fixstring (id->fw_rev, sizeof(id->fw_rev)); + fixstring (id->model, sizeof(id->model)); printk (" hd%c: %.40s, %dMB w/%dKB Cache, CHS=%d/%d/%d, MaxMult=%d\n", - dev+'a', id.model, id.cyls*id.heads*id.sectors/2048, - id.buf_size/2, hd_info[dev].cyl, hd_info[dev].head, - hd_info[dev].sect, id.max_multsect); - /* save drive info for later query via HDIO_GETIDENTITY */ - if (NULL != (hd_ident_info[dev] = (struct hd_driveid *)kmalloc(sizeof(id),GFP_ATOMIC))) - *hd_ident_info[dev] = id; - - /* Quantum drives go weird at this point, so reset them! */ - /* In fact, we should probably do a reset in any case in */ - /* case we changed the geometry */ - if (!strncmp(id.model, "QUANTUM", 7)) - reset = 1; - - /* flush remaining 384 (reserved/undefined) ID bytes: */ - insw(HD_DATA,(char *)&id,sizeof(id)/2); - insw(HD_DATA,(char *)&id,sizeof(id)/2); - insw(HD_DATA,(char *)&id,sizeof(id)/2); + dev+'a', id->model, id->cyls*id->heads*id->sectors/2048, + id->buf_size/2, hd_info[dev].cyl, hd_info[dev].head, + hd_info[dev].sect, id->max_multsect); + /* + * 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) + */ + if (!strncmp(id->model, "QUANTUM", 7)) + special_op[dev] = recalibrate[dev] = 1; } #if (HD_DELAY > 0) last_req = read_timer(); @@ -1040,7 +1038,7 @@ static void hd_geninit(void) } hd[i<<6].nr_sects = bios_info[i].head * bios_info[i].sect * bios_info[i].cyl; - hd_ident_info[i] = NULL; + hd_ident_info[i] = (struct hd_driveid *) kmalloc(512,GFP_KERNEL); special_op[i] = 1; } if (NR_HD) { diff --git a/drivers/block/ramdisk.c b/drivers/block/ramdisk.c index 85accd5d4c62..871def2c9eb9 100644 --- a/drivers/block/ramdisk.c +++ b/drivers/block/ramdisk.c @@ -22,6 +22,7 @@ #define RAMDISK_MINOR 1 +extern void wait_for_keypress(void); char *rd_start; int rd_length = 0; @@ -102,7 +103,7 @@ static void do_load(void) int i = 1; int nblocks; char *cp; - + /* * Check for a super block on the diskette. * The old-style boot/root diskettes had their RAM image @@ -164,9 +165,6 @@ static void do_load(void) } } -int floppy_grab_irq_and_dma(void); -void floppy_release_irq_and_dma(void); - /* * If the root device is the RAM disk, try to load it. * In order to do this, the root device is originally set to the @@ -174,6 +172,9 @@ void floppy_release_irq_and_dma(void); */ void rd_load(void) { + struct inode inode; + struct file filp; + /* If no RAM disk specified, give up early. */ if (!rd_length) return; @@ -184,12 +185,18 @@ void rd_load(void) if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR) return; -/* ugly, ugly */ - if (floppy_grab_irq_and_dma()) { - printk("Unable to grab floppy IRQ/DMA for loading ramdisk image\n"); - return; + /* for Slackware install disks */ + printk(KERN_NOTICE "VFS: Insert ramdisk floppy and press ENTER\n"); + wait_for_keypress(); + + memset(&filp, 0, sizeof(filp)); + memset(&inode, 0, sizeof(inode)); + inode.i_rdev = ROOT_DEV; + filp.f_mode = 1; /* read only */ + filp.f_inode = &inode; + if(blkdev_open(&inode, &filp) == 0 ){ + do_load(); + if(filp.f_op && filp.f_op->release) + filp.f_op->release(&inode,&filp); } - check_disk_change(ROOT_DEV); - do_load(); - floppy_release_irq_and_dma(); } diff --git a/drivers/char/console.c b/drivers/char/console.c index 2657e6e8a57c..4d39b09acc65 100644 --- a/drivers/char/console.c +++ b/drivers/char/console.c @@ -2100,7 +2100,8 @@ static void clear_selection() */ #define colourmap ((char *)0xa0000) -#define blackwmap ((char *)0xb0000) +/* Pauline Middelink reports that we should use 0xA0000 for the bwmap as well.. */ +#define blackwmap ((char *)0xa0000) #define cmapsz 8192 #define seq_port_reg (0x3c4) #define seq_port_val (0x3c5) diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 518487279fab..d64fe7416297 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -4,6 +4,7 @@ * - Thanks much to Gunter Windau for pointing out to me where the error * checking ought to be. * Copyright (C) 1993 by Nigel Gamble (added interrupt code) + * Copyright (C) 1994 by Alan Cox (Modularised it) */ #include @@ -17,6 +18,24 @@ #include #include +/* the BIOS manuals say there can be up to 4 lpt devices + * but I have not seen a board where the 4th address is listed + * if you have different hardware change the table below + * please let me know if you have different equipment + * if you have more than 3 printers, remember to increase LP_NO + */ +struct lp_struct lp_table[] = { + { 0x3bc, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, }, + { 0x378, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, }, + { 0x278, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, }, +}; +#define LP_NO 3 + +#ifdef MODULE +#include +#include "../../tools/version.h" +#endif + /* * All my debugging code assumes that you debug with only one printer at * a time. RWWH @@ -305,7 +324,9 @@ static int lp_open(struct inode * inode, struct file * file) } LP_F(minor) |= LP_BUSY; - +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif return 0; } @@ -321,6 +342,9 @@ static void lp_release(struct inode * inode, struct file * file) } LP_F(minor) &= ~LP_BUSY; +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif } @@ -418,6 +442,8 @@ static struct file_operations lp_fops = { lp_release }; +#ifndef MODULE + long lp_init(long kmem_start) { int offset = 0; @@ -450,3 +476,42 @@ long lp_init(long kmem_start) printk("lp_init: no lp devices found\n"); return kmem_start; } + +#else + +char kernel_version[]= UTS_RELEASE; + +int init_module(void) +{ + int offset = 0; + unsigned int testvalue = 0; + int count = 0; + + if (register_chrdev(LP_MAJOR,"lp",&lp_fops)) { + printk("unable to get major %d for line printer\n", LP_MAJOR); + return -EIO; + } + /* take on all known port values */ + for (offset = 0; offset < LP_NO; offset++) { + /* write to port & read back to check */ + outb_p( LP_DUMMY, LP_B(offset)); + for (testvalue = 0 ; testvalue < LP_DELAY ; testvalue++) + ; + testvalue = inb_p(LP_B(offset)); + if (testvalue == LP_DUMMY) { + LP_F(offset) |= LP_EXIST; + lp_reset(offset); + printk("lp_init: lp%d exists, ", offset); + if (LP_IRQ(offset)) + printk("using IRQ%d\n", LP_IRQ(offset)); + else + printk("using polling driver\n"); + count++; + } + } + if (count == 0) + printk("lp_init: no lp devices found\n"); + return 0; +} + +#endif diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index 11189111812d..11cb0f05c140 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -453,6 +453,8 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) goto handle_newline; } if (c == EOF_CHAR(tty)) { + if (tty->canon_head != tty->read_head) + set_bit(TTY_PUSH, &tty->flags); c = __DISABLED_CHAR; goto handle_newline; } @@ -718,24 +720,6 @@ static inline void copy_from_read_buf(struct tty_struct *tty, *nr -= n; } -/* - * Called to gobble up an immediately following EOF when there is no - * more room in buf (this can happen if the user "pushes" some - * characters using ^D). This prevents the next read() from falsely - * returning EOF. - */ -static inline void gobble_eof(struct tty_struct *tty) -{ - cli(); - if ((tty->read_cnt) && - (tty->read_buf[tty->read_tail] == __DISABLED_CHAR) && - clear_bit(tty->read_tail, &tty->read_flags)) { - tty->read_tail = (tty->read_tail+1) & (N_TTY_BUF_SIZE-1); - tty->read_cnt--; - } - sti(); -} - static int read_chan(struct tty_struct *tty, struct file *file, unsigned char *buf, unsigned int nr) { @@ -744,6 +728,9 @@ static int read_chan(struct tty_struct *tty, struct file *file, unsigned char *b = buf; int minimum, time; int retval = 0; + int size; + +do_it_again: if (!tty->read_buf) { printk("n_tty_read_chan: called with read_buf == NULL?!?\n"); @@ -858,7 +845,6 @@ static int read_chan(struct tty_struct *tty, struct file *file, put_fs_byte(c, b++); if (--nr) continue; - gobble_eof(tty); break; } if (--tty->canon_data < 0) { @@ -896,7 +882,14 @@ static int read_chan(struct tty_struct *tty, struct file *file, current->state = TASK_RUNNING; current->timeout = 0; - return (b - buf) ? b - buf : retval; + size = b - buf; + if (size && nr) + clear_bit(TTY_PUSH, &tty->flags); + if (!size && clear_bit(TTY_PUSH, &tty->flags)) + goto do_it_again; + if (!size && !retval) + clear_bit(TTY_PUSH, &tty->flags); + return (size ? size : retval); } static int write_chan(struct tty_struct * tty, struct file * file, diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 57cfa0c5407d..c194f9671594 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -1242,6 +1242,9 @@ static int tty_ioctl(struct inode * inode, struct file * file, case TIOCSTI: if ((current->tty != tty) && !suser()) return -EPERM; + retval = verify_area(VERIFY_READ, (void *) arg, 1); + if (retval) + return retval; ch = get_fs_byte((char *) arg); tty->ldisc.receive_buf(tty, &ch, &mbz, 1); return 0; @@ -1254,6 +1257,10 @@ static int tty_ioctl(struct inode * inode, struct file * file, sizeof (struct winsize)); return 0; case TIOCSWINSZ: + retval = verify_area(VERIFY_READ, (void *) arg, + sizeof (struct winsize)); + if (retval) + return retval; memcpy_fromfs(&tmp_ws, (struct winsize *) arg, sizeof (struct winsize)); if (memcmp(&tmp_ws, &tty->winsize, @@ -1279,6 +1286,9 @@ static int tty_ioctl(struct inode * inode, struct file * file, redirect = real_tty; return 0; case FIONBIO: + retval = verify_area(VERIFY_READ, (void *) arg, sizeof(long)); + if (retval) + return retval; arg = get_fs_long((unsigned long *) arg); if (arg) file->f_flags |= O_NONBLOCK; @@ -1371,6 +1381,9 @@ static int tty_ioctl(struct inode * inode, struct file * file, arg = get_fs_long((unsigned long *) arg); return tty_set_ldisc(tty, arg); case TIOCLINUX: + retval = verify_area(VERIFY_READ, (void *) arg, 1); + if (retval) + return retval; switch (get_fs_byte((char *)arg)) { case 0: diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index 3737bbf23f08..098ab9f3311d 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -98,6 +98,9 @@ static int set_termios(struct tty_struct * tty, unsigned long arg, int opt) return retval; if (opt & TERMIOS_TERMIO) { + retval = verify_area(VERIFY_READ, (void *) arg, sizeof(struct termio)); + if (retval) + return retval; tmp_termios = *tty->termios; memcpy_fromfs(&tmp_termio, (struct termio *) arg, sizeof (struct termio)); @@ -109,9 +112,13 @@ static int set_termios(struct tty_struct * tty, unsigned long arg, int opt) SET_LOW_BITS(tmp_termios.c_lflag, tmp_termio.c_lflag); memcpy(&tmp_termios.c_cc, &tmp_termio.c_cc, NCC); #undef SET_LOW_BITS - } else + } else { + retval = verify_area(VERIFY_READ, (void *) arg, sizeof(struct termios)); + if (retval) + return retval; memcpy_fromfs(&tmp_termios, (struct termios *) arg, sizeof (struct termios)); + } if ((opt & TERMIOS_FLUSH) && tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); @@ -307,6 +314,10 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, (unsigned long *) arg); return 0; case TIOCGLCKTRMIOS: + retval = verify_area(VERIFY_READ, (void *) arg, + sizeof (unsigned long)); + if (retval) + return retval; arg = get_fs_long((unsigned long *) arg); retval = verify_area(VERIFY_WRITE, (void *) arg, sizeof (struct termios)); @@ -319,7 +330,15 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, case TIOCSLCKTRMIOS: if (!suser()) return -EPERM; + retval = verify_area(VERIFY_READ, (void *) arg, + sizeof (unsigned long)); + if (retval) + return retval; arg = get_fs_long((unsigned long *) arg); + retval = verify_area(VERIFY_READ, (void *) arg, + sizeof (struct termios)); + if (retval) + return retval; memcpy_fromfs(&real_tty->termios_locked, (struct termios *) arg, sizeof (struct termios)); diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 3cb276b64ee9..183d49a2f6d2 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -78,6 +78,7 @@ make one yourself. The wiring is: #include #include #include +#include #include #include @@ -196,7 +197,7 @@ plip_init(struct device *dev) struct net_local *pl; /* Check that there is something at base_addr. */ - outb(0x00, PAR_CONTROL(dev)); + outb(LP_PINITP, PAR_CONTROL(dev)); outb(0x00, PAR_DATA(dev)); if (inb(PAR_DATA(dev)) != 0x00) return -ENODEV; @@ -212,9 +213,9 @@ plip_init(struct device *dev) printk("%s: configured for parallel port at %#3x", dev->name, dev->base_addr); autoirq_setup(0); - outb(0x00, PAR_CONTROL(dev)); - outb(0x10, PAR_CONTROL(dev)); - outb(0x00, PAR_CONTROL(dev)); + outb(LP_PINITP|LP_PSELECP, PAR_CONTROL(dev)); + outb(LP_PINITP|LP_PSELECP|LP_PINTEN, PAR_CONTROL(dev)); + outb(LP_PINITP|LP_PSELECP, PAR_CONTROL(dev)); dev->irq = autoirq_report(1); if (dev->irq) printk(", probed IRQ %d.\n", dev->irq); @@ -368,7 +369,7 @@ plip_open(struct device *dev) irq2dev_map[dev->irq] = dev; sti(); /* enable rx interrupt. */ - outb(0x10, PAR_CONTROL(dev)); + outb(LP_PINITP|LP_PSELECP|LP_PINTEN, PAR_CONTROL(dev)); plip_device_clear(dev); dev->start = 1; #ifdef MODULE @@ -393,7 +394,7 @@ plip_close(struct device *dev) /* make sure that we don't register the timer */ del_timer(&lp->tl); /* release the interrupt. */ - outb(0x00, PAR_CONTROL(dev)); + outb(LP_PINITP|LP_PSELECP, PAR_CONTROL(dev)); #ifdef MODULE MOD_DEC_USE_COUNT; #endif diff --git a/drivers/sound/dma.h b/drivers/sound/dma.h deleted file mode 100644 index 1196fdff1de1..000000000000 --- a/drivers/sound/dma.h +++ /dev/null @@ -1,266 +0,0 @@ -/* $Id: dma.h,v 1.7 1992/12/14 00:29:34 root Exp root $ - * linux/include/asm/dma.h: Defines for using and allocating dma channels. - * Written by Hennus Bergman, 1992. - * High DMA channel support & info by Hannu Savolainen - * and John Boyd, Nov. 1992. - */ - -#ifndef _ASM_DMA_H -#define _ASM_DMA_H - -#include /* need byte IO */ - -#define deb_outb(x,y) {printk("out %02x, %02x\n", x, y);outb(x,y);} - - -#ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER -#define outb outb_p -#endif - -/* - * NOTES about DMA transfers: - * - * controller 1: channels 0-3, byte operations, ports 00-1F - * controller 2: channels 4-7, word operations, ports C0-DF - * - * - ALL registers are 8 bits only, regardless of transfer size - * - channel 4 is not used - cascades 1 into 2. - * - channels 0-3 are byte - addresses/counts are for physical bytes - * - channels 5-7 are word - addresses/counts are for physical words - * - transfers must not cross physical 64K (0-3) or 128K (5-7) boundaries - * - transfer count loaded to registers is 1 less than actual count - * - controller 2 offsets are all even (2x offsets for controller 1) - * - page registers for 5-7 don't use data bit 0, represent 128K pages - * - page registers for 0-3 use bit 0, represent 64K pages - * - * DMA transfers are limited to the lower 16MB of _physical_ memory. - * Note that addresses loaded into registers must be _physical_ addresses, - * not logical addresses (which may differ if paging is active). - * - * Address mapping for channels 0-3: - * - * A23 ... A16 A15 ... A8 A7 ... A0 (Physical addresses) - * | ... | | ... | | ... | - * | ... | | ... | | ... | - * | ... | | ... | | ... | - * P7 ... P0 A7 ... A0 A7 ... A0 - * | Page | Addr MSB | Addr LSB | (DMA registers) - * - * Address mapping for channels 5-7: - * - * A23 ... A17 A16 A15 ... A9 A8 A7 ... A1 A0 (Physical addresses) - * | ... | \ \ ... \ \ \ ... \ \ - * | ... | \ \ ... \ \ \ ... \ (not used) - * | ... | \ \ ... \ \ \ ... \ - * P7 ... P1 (0) A7 A6 ... A0 A7 A6 ... A0 - * | Page | Addr MSB | Addr LSB | (DMA registers) - * - * Again, channels 5-7 transfer _physical_ words (16 bits), so addresses - * and counts _must_ be word-aligned (the lowest address bit is _ignored_ at - * the hardware level, so odd-byte transfers aren't possible). - * - * Transfer count (_not # bytes_) is limited to 64K, represented as actual - * count - 1 : 64K => 0xFFFF, 1 => 0x0000. Thus, count is always 1 or more, - * and up to 128K bytes may be transferred on channels 5-7 in one operation. - * - */ - -#define MAX_DMA_CHANNELS 8 - -/* 8237 DMA controllers */ -#define IO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */ -#define IO_DMA2_BASE 0xC0 /* 16 bit master DMA, ch 4(=slave input)..7 */ - -/* DMA controller registers */ -#define DMA1_CMD_REG 0x08 /* command register (w) */ -#define DMA1_STAT_REG 0x08 /* status register (r) */ -#define DMA1_REQ_REG 0x09 /* request register (w) */ -#define DMA1_MASK_REG 0x0A /* single-channel mask (w) */ -#define DMA1_MODE_REG 0x0B /* mode register (w) */ -#define DMA1_CLEAR_FF_REG 0x0C /* clear pointer flip-flop (w) */ -#define DMA1_TEMP_REG 0x0D /* Temporary Register (r) */ -#define DMA1_RESET_REG 0x0D /* Master Clear (w) */ -#define DMA1_CLR_MASK_REG 0x0E /* Clear Mask */ -#define DMA1_MASK_ALL_REG 0x0F /* all-channels mask (w) */ - -#define DMA2_CMD_REG 0xD0 /* command register (w) */ -#define DMA2_STAT_REG 0xD0 /* status register (r) */ -#define DMA2_REQ_REG 0xD2 /* request register (w) */ -#define DMA2_MASK_REG 0xD4 /* single-channel mask (w) */ -#define DMA2_MODE_REG 0xD6 /* mode register (w) */ -#define DMA2_CLEAR_FF_REG 0xD8 /* clear pointer flip-flop (w) */ -#define DMA2_TEMP_REG 0xDA /* Temporary Register (r) */ -#define DMA2_RESET_REG 0xDA /* Master Clear (w) */ -#define DMA2_CLR_MASK_REG 0xDC /* Clear Mask */ -#define DMA2_MASK_ALL_REG 0xDE /* all-channels mask (w) */ - -#define DMA_ADDR_0 0x00 /* DMA address registers */ -#define DMA_ADDR_1 0x02 -#define DMA_ADDR_2 0x04 -#define DMA_ADDR_3 0x06 -#define DMA_ADDR_4 0xC0 -#define DMA_ADDR_5 0xC4 -#define DMA_ADDR_6 0xC8 -#define DMA_ADDR_7 0xCC - -#define DMA_CNT_0 0x01 /* DMA count registers */ -#define DMA_CNT_1 0x03 -#define DMA_CNT_2 0x05 -#define DMA_CNT_3 0x07 -#define DMA_CNT_4 0xC2 -#define DMA_CNT_5 0xC6 -#define DMA_CNT_6 0xCA -#define DMA_CNT_7 0xCE - -#define DMA_PAGE_0 0x87 /* DMA page registers */ -#define DMA_PAGE_1 0x83 -#define DMA_PAGE_2 0x81 -#define DMA_PAGE_3 0x82 -#define DMA_PAGE_5 0x8B -#define DMA_PAGE_6 0x89 -#define DMA_PAGE_7 0x8A - -#define DMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */ -#define DMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */ -#define DMA_MODE_CASCADE 0xC0 /* pass thru DREQ->HRQ, DACK<-HLDA only */ - -/* enable/disable a specific DMA channel */ -static __inline__ void enable_dma(unsigned int dmanr) -{ - if (dmanr<=3) - deb_outb(dmanr, DMA1_MASK_REG) - else - deb_outb(dmanr & 3, DMA2_MASK_REG); -} - -static __inline__ void disable_dma(unsigned int dmanr) -{ - if (dmanr<=3) - deb_outb(dmanr | 4, DMA1_MASK_REG) - else - deb_outb((dmanr & 3) | 4, DMA2_MASK_REG); -} - -/* Clear the 'DMA Pointer Flip Flop'. - * Write 0 for LSB/MSB, 1 for MSB/LSB access. - * Use this once to initialize the FF to a known state. - * After that, keep track of it. :-) - * --- In order to do that, the DMA routines below should --- - * --- only be used while interrupts are disabled! --- - */ -static __inline__ void clear_dma_ff(unsigned int dmanr) -{ - if (dmanr<=3) - deb_outb(0, DMA1_CLEAR_FF_REG) - else - deb_outb(0, DMA2_CLEAR_FF_REG); -} - -/* set mode (above) for a specific DMA channel */ -static __inline__ void set_dma_mode(unsigned int dmanr, char mode) -{ - if (dmanr<=3) - deb_outb(mode | dmanr, DMA1_MODE_REG) - else - deb_outb(mode | (dmanr&3), DMA2_MODE_REG); -} - -/* Set only the page register bits of the transfer address. - * This is used for successive transfers when we know the contents of - * the lower 16 bits of the DMA current address register, but a 64k boundary - * may have been crossed. - */ -static __inline__ void set_dma_page(unsigned int dmanr, char pagenr) -{ - switch(dmanr) { - case 0: - deb_outb(pagenr, DMA_PAGE_0); - break; - case 1: - deb_outb(pagenr, DMA_PAGE_1); - break; - case 2: - deb_outb(pagenr, DMA_PAGE_2); - break; - case 3: - deb_outb(pagenr, DMA_PAGE_3); - break; - case 5: - deb_outb(pagenr & 0xfe, DMA_PAGE_5); - break; - case 6: - deb_outb(pagenr & 0xfe, DMA_PAGE_6); - break; - case 7: - deb_outb(pagenr & 0xfe, DMA_PAGE_7); - break; - } -} - - -/* Set transfer address & page bits for specific DMA channel. - * Assumes dma flipflop is clear. - */ -static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a) -{ - set_dma_page(dmanr, a>>16); - if (dmanr <= 3) { - deb_outb( a & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE ); - deb_outb( (a>>8) & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE ) - } else { - deb_outb( (a>>1) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE ); - deb_outb( (a>>9) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE ); - } -} - - -/* Set transfer size (max 64k for DMA1..3, 128k for DMA5..7) for - * a specific DMA channel. - * You must ensure the parameters are valid. - * NOTE: from a manual: "the number of transfers is one more - * than the initial word count"! This is taken into account. - * Assumes dma flip-flop is clear. - * NOTE 2: "count" represents _bytes_ and must be even for channels 5-7. - */ -static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count) -{ - count--; - if (dmanr <= 3) { - deb_outb( count & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE ); - deb_outb( (count>>8) & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE ); - } else { - deb_outb( (count>>1) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE ); - deb_outb( (count>>9) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE ); - } -} - - -/* Get DMA residue count. After a DMA transfer, this - * should return zero. Reading this while a DMA transfer is - * still in progress will return unpredictable results. - * If called before the channel has been used, it may return 1. - * Otherwise, it returns the number of _bytes_ left to transfer. - * - * Assumes DMA flip-flop is clear. - */ -static __inline__ int get_dma_residue(unsigned int dmanr) -{ - unsigned int io_port = (dmanr<=3)? ((dmanr&3)<<1) + 1 + IO_DMA1_BASE - : ((dmanr&3)<<2) + 2 + IO_DMA2_BASE; - - /* using short to get 16-bit wrap around */ - unsigned short count; - - count = 1 + inb(io_port); - count += inb(io_port) << 8; - - return (dmanr<=3)? count : (count<<1); -} - - -/* These are in kernel/dma.c: */ -extern int request_dma(unsigned int dmanr,char * deviceID); /* reserve a DMA channel */ -extern void free_dma(unsigned int dmanr); /* release it again */ - - -#endif /* _ASM_DMA_H */ diff --git a/fs/buffer.c b/fs/buffer.c index aade8cafccbc..75bbbe580fc8 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -147,6 +147,7 @@ static int sync_buffers(dev_t dev, int wait) 2) wait for completion by waiting for all buffers to unlock. */ repeat: retry = 0; + repeat2: ncount = 0; /* We search all lists as a failsafe mechanism, not because we expect there to be dirty buffers on any of the other lists. */ @@ -170,6 +171,7 @@ static int sync_buffers(dev_t dev, int wait) continue; } wait_on_buffer (bh); + goto repeat2; } /* If an unlocked buffer is not uptodate, there has been an IO error. Skip it. */ @@ -183,6 +185,9 @@ static int sync_buffers(dev_t dev, int wait) on the third pass. */ if (!bh->b_dirt || pass>=2) continue; + /* don't bother about locked buffers */ + if (bh->b_lock) + continue; bh->b_count++; bh->b_flushtime = 0; ll_rw_block(WRITE, 1, &bh); @@ -1735,31 +1740,37 @@ asmlinkage int sys_bdflush(int func, int data) int ncount; struct buffer_head * bh, *next; - if(!suser()) return -EPERM; + if (!suser()) + return -EPERM; - if(func == 1) + if (func == 1) return sync_old_buffers(); /* Basically func 0 means start, 1 means read param 1, 2 means write param 1, etc */ - if(func >= 2){ + if (func >= 2) { i = (func-2) >> 1; - if (i < 0 || i >= N_PARAM) return -EINVAL; + if (i < 0 || i >= N_PARAM) + return -EINVAL; if((func & 1) == 0) { error = verify_area(VERIFY_WRITE, (void *) data, sizeof(int)); - if(error) return error; + if (error) + return error; put_fs_long(bdf_prm.data[i], data); return 0; }; - if(data < bdflush_min[i] || data > bdflush_max[i]) return -EINVAL; + if (data < bdflush_min[i] || data > bdflush_max[i]) + return -EINVAL; bdf_prm.data[i] = data; return 0; }; - if(bdflush_running++) return -EBUSY; /* Only one copy of this running at one time */ + if (bdflush_running) + return -EBUSY; /* Only one copy of this running at one time */ + bdflush_running++; /* OK, from here on is the daemon */ - while(1==1){ + for (;;) { #ifdef DEBUG printk("bdflush() activated..."); #endif diff --git a/fs/exec.c b/fs/exec.c index 99b38210d4bc..838072625d8b 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -728,10 +728,10 @@ restart_interp: if (!fn) break; retval = fn(&bprm, regs); - if (retval == 0) { + if (retval >= 0) { iput(bprm.inode); current->did_exec = 1; - return 0; + return retval; } if (retval != -ENOEXEC) break; diff --git a/fs/ext/dir.c b/fs/ext/dir.c index 0f387a80ba61..3c94fa3e2bc4 100644 --- a/fs/ext/dir.c +++ b/fs/ext/dir.c @@ -72,7 +72,7 @@ static int ext_readdir(struct inode * inode, struct file * filp, if (!inode || !S_ISDIR(inode->i_mode)) return -EBADF; - if (filp->f_pos % 8 != 0) + if ((filp->f_pos & 7) != 0) return -EBADF; while (filp->f_pos < inode->i_size) { offset = filp->f_pos & 1023; diff --git a/fs/ext2/file.c b/fs/ext2/file.c index 3da0ef2cb3e1..b615c585a31e 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -232,11 +232,13 @@ static int ext2_file_write (struct inode * inode, struct file * filp, { off_t pos; int written, c; - struct buffer_head * bh; + struct buffer_head * bh, *bufferlist[NBUF]; char * p; struct super_block * sb; int err; + int i,buffercount,write_error; + write_error = buffercount = 0; if (!inode) { printk("ext2_file_write: inode = NULL\n"); return -EINVAL; @@ -294,12 +296,32 @@ static int ext2_file_write (struct inode * inode, struct file * filp, buf += c; bh->b_uptodate = 1; mark_buffer_dirty(bh, 0); - if (filp->f_flags & O_SYNC) { - ll_rw_block (WRITE, 1, &bh); - wait_on_buffer (bh); + if (filp->f_flags & O_SYNC) + bufferlist[buffercount++] = bh; + else + brelse(bh); + if (buffercount == NBUF){ + ll_rw_block(WRITE, buffercount, bufferlist); + for(i=0; ib_uptodate) + write_error=1; + brelse(bufferlist[i]); + } + buffercount=0; } - brelse (bh); + if(write_error) + break; } + if ( buffercount ){ + ll_rw_block(WRITE, buffercount, bufferlist); + for(i=0; ib_uptodate) + write_error=1; + brelse(bufferlist[i]); + } + } if (pos > inode->i_size) inode->i_size = pos; if (filp->f_flags & O_SYNC) diff --git a/fs/hpfs/hpfs.h b/fs/hpfs/hpfs.h index 19c9849a7234..3121a415d317 100644 --- a/fs/hpfs/hpfs.h +++ b/fs/hpfs/hpfs.h @@ -92,7 +92,11 @@ struct hpfs_spare_block { unsigned magic; /* f991 1849 */ unsigned magic1; /* fa52 29c5, more magic? */ - unsigned dirty; /* 0 clean, 1 "improperly stopped" */ + + unsigned dirty: 1; /* 0 clean, 1 "improperly stopped" */ + unsigned flag1234: 4; /* unknown flags */ + unsigned fast: 1; /* partition was fast formatted */ + unsigned flag6to31: 26; /* unknown flags */ secno hotfix_map; /* info about remapped bad sectors */ unsigned n_spares_used; /* number of hotfixes */ diff --git a/fs/locks.c b/fs/locks.c index 7b1c318f461e..9c90a2e39b05 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -109,7 +109,7 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l) if (fd >= NR_OPEN || !(filp = current->files->fd[fd])) return -EBADF; - error = verify_area(VERIFY_WRITE, l, sizeof(*l)); + error = verify_area(VERIFY_READ, l, sizeof(*l)); if (error) return error; memcpy_fromfs(&flock, l, sizeof(flock)); diff --git a/fs/nfs/file.c b/fs/nfs/file.c index f44598708afb..2d823bf0c5f7 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -3,6 +3,12 @@ * * Copyright (C) 1992 Rick Sladkey * + * Changes Copyright (C) 1994 by Florian La Roche + * - Do not copy data too often around in the kernel. + * - In nfs_file_read the return value of kmalloc wasn't checked. + * - Put in a better version of read look-ahead buffering. Original idea + * and implementation by Wai S Kok elekokw@ee.nus.sg. + * * nfs regular file handling functions */ @@ -21,7 +27,6 @@ static int nfs_file_read(struct inode *, struct file *, char *, int); static int nfs_file_write(struct inode *, struct file *, char *, int); static int nfs_fsync(struct inode *, struct file *); -extern int nfs_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma); static struct file_operations nfs_file_operations = { NULL, /* lseek - default */ @@ -53,6 +58,32 @@ struct inode_operations nfs_file_inode_operations = { NULL /* truncate */ }; +/* Once data is inserted, it can only be deleted, if (in_use==0). */ +struct read_cache { + int in_use; /* currently in use? */ + unsigned long inode_num; /* inode number */ + off_t file_pos; /* file position */ + int len; /* size of data */ + unsigned long time; /* time, this entry was inserted */ + char * buf; /* data */ + int buf_size; /* size of buffer */ +}; + +#define READ_CACHE_SIZE 5 +#define EXPIRE_CACHE (HZ * 3) /* keep no longer than 3 seconds */ + +unsigned long num_requests = 0; +unsigned long num_cache_hits = 0; + +static int tail = 0; /* next cache slot to replace */ + +static struct read_cache cache[READ_CACHE_SIZE] = { + { 0, 0, -1, 0, 0, NULL, 0 }, + { 0, 0, -1, 0, 0, NULL, 0 }, + { 0, 0, -1, 0, 0, NULL, 0 }, + { 0, 0, -1, 0, 0, NULL, 0 }, + { 0, 0, -1, 0, 0, NULL, 0 } }; + static int nfs_fsync(struct inode *inode, struct file *file) { return 0; @@ -61,10 +92,7 @@ static int nfs_fsync(struct inode *inode, struct file *file) static int nfs_file_read(struct inode *inode, struct file *file, char *buf, int count) { - int result; - int hunk; - int i; - int n; + int result, hunk, i, n, fs; struct nfs_fattr fattr; char *data; off_t pos; @@ -79,46 +107,88 @@ static int nfs_file_read(struct inode *inode, struct file *file, char *buf, return -EINVAL; } pos = file->f_pos; - if (file->f_pos + count > inode->i_size) + if (pos + count > inode->i_size) count = inode->i_size - pos; if (count <= 0) return 0; + ++num_requests; + cli(); + for (i = 0; i < READ_CACHE_SIZE; i++) + if ((cache[i].inode_num == inode->i_ino) + && (cache[i].file_pos <= pos) + && (cache[i].file_pos + cache[i].len >= pos + count) + && (abs(jiffies - cache[i].time) <= EXPIRE_CACHE)) + break; + if (i < READ_CACHE_SIZE) { + ++cache[i].in_use; + sti(); + ++num_cache_hits; + memcpy_tofs(buf, cache[i].buf + pos - cache[i].file_pos, count); + --cache[i].in_use; + file->f_pos += count; + return count; + } + sti(); n = NFS_SERVER(inode)->rsize; - data = (char *) kmalloc(n, GFP_KERNEL); - for (i = 0; i < count; i += n) { - hunk = count - i; - if (hunk > n) - hunk = n; + for (i = 0; i < count - n; i += n) { result = nfs_proc_read(NFS_SERVER(inode), NFS_FH(inode), - pos, hunk, data, &fattr); - if (result < 0) { - kfree_s(data, n); + pos, n, buf, &fattr, 1); + if (result < 0) return result; - } - memcpy_tofs(buf, data, result); pos += result; buf += result; if (result < n) { - i += result; - break; + file->f_pos = pos; + nfs_refresh_inode(inode, &fattr); + return i + result; } } - file->f_pos = pos; - kfree_s(data, n); + fs = 0; + if (!(data = (char *)kmalloc(n, GFP_KERNEL))) { + data = buf; + fs = 1; + } + result = nfs_proc_read(NFS_SERVER(inode), NFS_FH(inode), + pos, n, data, &fattr, fs); + if (result < 0) { + if (!fs) + kfree_s(data, n); + return result; + } + hunk = count - i; + if (result < hunk) + hunk = result; + if (fs) { + file->f_pos = pos + hunk; + nfs_refresh_inode(inode, &fattr); + return i + hunk; + } + memcpy_tofs(buf, data, hunk); + file->f_pos = pos + hunk; nfs_refresh_inode(inode, &fattr); - return i; + cli(); + if (cache[tail].in_use == 0) { + if (cache[tail].buf) + kfree_s(cache[tail].buf, cache[tail].buf_size); + cache[tail].buf = data; + cache[tail].buf_size = n; + cache[tail].inode_num = inode->i_ino; + cache[tail].file_pos = pos; + cache[tail].len = result; + cache[tail].time = jiffies; + if (++tail >= READ_CACHE_SIZE) + tail = 0; + } else + kfree_s(data, n); + sti(); + return i + hunk; } static int nfs_file_write(struct inode *inode, struct file *file, char *buf, int count) { - int result; - int hunk; - int i; - int n; + int result, hunk, i, n, pos; struct nfs_fattr fattr; - char *data; - int pos; if (!inode) { printk("nfs_file_write: inode = NULL\n"); @@ -135,18 +205,14 @@ static int nfs_file_write(struct inode *inode, struct file *file, char *buf, if (file->f_flags & O_APPEND) pos = inode->i_size; n = NFS_SERVER(inode)->wsize; - data = (char *) kmalloc(n, GFP_KERNEL); for (i = 0; i < count; i += n) { hunk = count - i; if (hunk >= n) hunk = n; - memcpy_fromfs(data, buf, hunk); result = nfs_proc_write(NFS_SERVER(inode), NFS_FH(inode), - pos, hunk, data, &fattr); - if (result < 0) { - kfree_s(data, n); + pos, hunk, buf, &fattr); + if (result < 0) return result; - } pos += hunk; buf += hunk; if (hunk < n) { @@ -155,7 +221,6 @@ static int nfs_file_write(struct inode *inode, struct file *file, char *buf, } } file->f_pos = pos; - kfree_s(data, n); nfs_refresh_inode(inode, &fattr); return i; } diff --git a/fs/nfs/mmap.c b/fs/nfs/mmap.c index d2342e5ba8a7..811176a69e5f 100644 --- a/fs/nfs/mmap.c +++ b/fs/nfs/mmap.c @@ -54,7 +54,7 @@ static unsigned long nfs_file_mmap_nopage(struct vm_area_struct * area, if (hunk > n) hunk = n; result = nfs_proc_read(NFS_SERVER(inode), NFS_FH(inode), - pos, hunk, (char *) (page + i), &fattr); + pos, hunk, (char *) (page + i), &fattr, 0); if (result < 0) break; pos += result; diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index f49963aa2104..d06e988f8d98 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -9,10 +9,17 @@ * so at last we can have decent(ish) throughput off a * Sun server. * + * Coding optimized and cleaned up by Florian La Roche. + * Note: Error returns are optimized for NFS_OK, which isn't translated via + * nfs_stat_to_errno(), but happens to be already the right return code. + * * FixMe: We ought to define a sensible small max size for * things like getattr that are tiny packets and use the * old get_free_page stuff with it. * + * Also, the code currently doesn't check the size of the packet, when + * it decodes the packet. + * * Feel free to fix it and mail me the diffs if it worries you. */ @@ -36,6 +43,7 @@ #include #include #include +#include #ifdef NFS_PROC_DEBUG @@ -52,6 +60,9 @@ static int proc_debug = 0; #endif /* !NFS_PROC_DEBUG */ +/* Mapping from NFS error code to "errno" error code. */ +#define errno_NFSERR_IO EIO + static int *nfs_rpc_header(int *p, int procedure, int ruid); static int *nfs_rpc_verify(int *p); static int nfs_stat_to_errno(int stat); @@ -61,11 +72,30 @@ static int nfs_stat_to_errno(int stat); */ #define NFS_SLACK_SPACE 1024 /* Total overkill */ +/* !!! Be careful, this constant is now also used in sock.c... + We should easily convert to not using it anymore for most cases... */ static inline int *nfs_rpc_alloc(int size) { - size+=NFS_SLACK_SPACE; /* Allow for the NFS crap as well as buffer */ - return (int *)kmalloc(size,GFP_KERNEL); +#if 1 + /* Allow for the NFS crap as well as buffer */ + return (int *)kmalloc(size+NFS_SLACK_SPACE,GFP_KERNEL); +#else + /* If kmalloc fails, then we will give an EIO to user level. + (Please correct me, I am wron here... ??) This is not + desirable, but it is also not desirable to execute the + following code: Just loop until we get memory, call schedule(), + so that other processes are run inbetween (and hopefully give + some memory back). Florian + */ + int i; + + while (!(i = (int *)kmalloc(size+NFS_SLACK_SPACE,GFP_KERNEL))) { + /* printk("NFS: call schedule\n"); */ + schedule(); + } + return i; +#endif } static inline void nfs_rpc_free(int *p) @@ -78,68 +108,73 @@ static inline void nfs_rpc_free(int *p) * between machine dependent and xdr data formats. */ +#define QUADLEN(len) (((len) + 3) >> 2) + static inline int *xdr_encode_fhandle(int *p, struct nfs_fh *fhandle) { *((struct nfs_fh *) p) = *fhandle; - p += (sizeof (*fhandle) + 3) >> 2; - return p; + return p + QUADLEN(sizeof(*fhandle)); } static inline int *xdr_decode_fhandle(int *p, struct nfs_fh *fhandle) { *fhandle = *((struct nfs_fh *) p); - p += (sizeof (*fhandle) + 3) >> 2; - return p; + return p + QUADLEN(sizeof(*fhandle)); } static inline int *xdr_encode_string(int *p, const char *string) { - int len, quadlen; - - len = strlen(string); - quadlen = (len + 3) >> 2; + int len = strlen(string); + int quadlen = QUADLEN(len); + + p[quadlen] = 0; *p++ = htonl(len); - memcpy((char *) p, string, len); - memset(((char *) p) + len, '\0', (quadlen << 2) - len); - p += quadlen; - return p; + memcpy(p, string, len); + return p + quadlen; } -static inline int *xdr_decode_string(int *p, char *string, int maxlen) +static inline int *xdr_decode_string(int *p, char *string, unsigned int maxlen) { - unsigned int len; - - len = ntohl(*p++); + unsigned int len = ntohl(*p++); if (len > maxlen) return NULL; - memcpy(string, (char *) p, len); + memcpy(string, p, len); string[len] = '\0'; - p += (len + 3) >> 2; - return p; + return p + QUADLEN(len); +} + +static inline int *xdr_decode_string2(int *p, char **string, unsigned int *len, + unsigned int maxlen) +{ + *len = ntohl(*p++); + if (*len > maxlen) + return NULL; + *string = (char *) p; + return p + QUADLEN(*len); } + static inline int *xdr_encode_data(int *p, char *data, int len) { - int quadlen; + int quadlen = QUADLEN(len); - quadlen = (len + 3) >> 2; + p[quadlen] = 0; *p++ = htonl(len); - memcpy((char *) p, data, len); - memset(((char *) p) + len, '\0', (quadlen << 2) - len); - p += quadlen; - return p; + memcpy_fromfs(p, data, len); + return p + quadlen; } -static inline int *xdr_decode_data(int *p, char *data, int *lenp, int maxlen) +static inline int *xdr_decode_data(int *p, char *data, int *lenp, int maxlen, + int fs) { - unsigned int len; - - len = *lenp = ntohl(*p++); + unsigned len = *lenp = ntohl(*p++); if (len > maxlen) return NULL; - memcpy(data, (char *) p, len); - p += (len + 3) >> 2; - return p; + if (fs) + memcpy_tofs(data, p, len); + else + memcpy(data, p, len); + return p + QUADLEN(len); } static int *xdr_decode_fattr(int *p, struct nfs_fattr *fattr) @@ -214,15 +249,16 @@ int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, retry: p = nfs_rpc_header(p0, NFSPROC_GETATTR, ruid); p = xdr_encode_fhandle(p, fhandle); - if ((status = nfs_rpc_call(server, p0, p)) < 0) { + if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) { nfs_rpc_free(p0); return status; } if (!(p = nfs_rpc_verify(p0))) - status = NFSERR_IO; + status = -errno_NFSERR_IO; else if ((status = ntohl(*p++)) == NFS_OK) { p = xdr_decode_fattr(p, fattr); PRINTK("NFS reply getattr\n"); + /* status = 0; */ } else { if (!ruid && current->fsuid == 0 && current->uid != 0) { @@ -230,9 +266,10 @@ retry: goto retry; } PRINTK("NFS reply getattr failed = %d\n", status); + status = -nfs_stat_to_errno(status); } nfs_rpc_free(p0); - return -nfs_stat_to_errno(status); + return status; } int nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle, @@ -249,15 +286,16 @@ retry: p = nfs_rpc_header(p0, NFSPROC_SETATTR, ruid); p = xdr_encode_fhandle(p, fhandle); p = xdr_encode_sattr(p, sattr); - if ((status = nfs_rpc_call(server, p0, p)) < 0) { + if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) { nfs_rpc_free(p0); return status; } if (!(p = nfs_rpc_verify(p0))) - status = NFSERR_IO; + status = -errno_NFSERR_IO; else if ((status = ntohl(*p++)) == NFS_OK) { p = xdr_decode_fattr(p, fattr); PRINTK("NFS reply setattr\n"); + /* status = 0; */ } else { if (!ruid && current->fsuid == 0 && current->uid != 0) { @@ -265,9 +303,10 @@ retry: goto retry; } PRINTK("NFS reply setattr failed = %d\n", status); + status = -nfs_stat_to_errno(status); } nfs_rpc_free(p0); - return -nfs_stat_to_errno(status); + return status; } int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir, const char *name, @@ -288,16 +327,17 @@ retry: p = nfs_rpc_header(p0, NFSPROC_LOOKUP, ruid); p = xdr_encode_fhandle(p, dir); p = xdr_encode_string(p, name); - if ((status = nfs_rpc_call(server, p0, p)) < 0) { + if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) { nfs_rpc_free(p0); return status; } if (!(p = nfs_rpc_verify(p0))) - status = NFSERR_IO; + status = -errno_NFSERR_IO; else if ((status = ntohl(*p++)) == NFS_OK) { p = xdr_decode_fhandle(p, fhandle); p = xdr_decode_fattr(p, fattr); PRINTK("NFS reply lookup\n"); + /* status = 0; */ } else { if (!ruid && current->fsuid == 0 && current->uid != 0) { @@ -305,37 +345,35 @@ retry: goto retry; } PRINTK("NFS reply lookup failed = %d\n", status); + status = -nfs_stat_to_errno(status); } nfs_rpc_free(p0); - return -nfs_stat_to_errno(status); + return status; } int nfs_proc_readlink(struct nfs_server *server, struct nfs_fh *fhandle, - char *res) + int **p0, char **string, unsigned int *len, unsigned int maxlen) { - int *p, *p0; - int status; - int ruid = 0; + int *p; + int status, ruid = 0; PRINTK("NFS call readlink\n"); - if (!(p0 = nfs_rpc_alloc(server->rsize))) + if (!(*p0 = nfs_rpc_alloc(server->rsize))) return -EIO; retry: - p = nfs_rpc_header(p0, NFSPROC_READLINK, ruid); + p = nfs_rpc_header(*p0, NFSPROC_READLINK, ruid); p = xdr_encode_fhandle(p, fhandle); - if ((status = nfs_rpc_call(server, p0, p)) < 0) { - nfs_rpc_free(p0); + if ((status = nfs_rpc_call(server, *p0, p, server->rsize)) < 0) return status; - } - if (!(p = nfs_rpc_verify(p0))) - status = NFSERR_IO; + if (!(p = nfs_rpc_verify(*p0))) + status = -errno_NFSERR_IO; else if ((status = ntohl(*p++)) == NFS_OK) { - if (!(p = xdr_decode_string(p, res, NFS_MAXPATHLEN))) { + if (!(p = xdr_decode_string2(p, string, len, maxlen))) { printk("nfs_proc_readlink: giant pathname\n"); - status = NFSERR_IO; + status = -errno_NFSERR_IO; } - else - PRINTK("NFS reply readlink %s\n", res); + else /* status = 0, */ + PRINTK("NFS reply readlink\n"); } else { if (!ruid && current->fsuid == 0 && current->uid != 0) { @@ -343,18 +381,18 @@ retry: goto retry; } PRINTK("NFS reply readlink failed = %d\n", status); + status = -nfs_stat_to_errno(status); } - nfs_rpc_free(p0); - return -nfs_stat_to_errno(status); + return status; } int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle, - int offset, int count, char *data, struct nfs_fattr *fattr) + int offset, int count, char *data, struct nfs_fattr *fattr, int fs) { int *p, *p0; int status; int ruid = 0; - int len = 0; /* = 0 is for gcc */ + int len; PRINTK("NFS call read %d @ %d\n", count, offset); if (!(p0 = nfs_rpc_alloc(server->rsize))) @@ -365,20 +403,22 @@ retry: *p++ = htonl(offset); *p++ = htonl(count); *p++ = htonl(count); /* traditional, could be any value */ - if ((status = nfs_rpc_call(server, p0, p)) < 0) { + if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) { nfs_rpc_free(p0); return status; } if (!(p = nfs_rpc_verify(p0))) - status = NFSERR_IO; + status = -errno_NFSERR_IO; else if ((status = ntohl(*p++)) == NFS_OK) { p = xdr_decode_fattr(p, fattr); - if (!(p = xdr_decode_data(p, data, &len, count))) { + if (!(p = xdr_decode_data(p, data, &len, count, fs))) { printk("nfs_proc_read: giant data size\n"); - status = NFSERR_IO; + status = -errno_NFSERR_IO; } - else + else { + status = len; PRINTK("NFS reply read %d\n", len); + } } else { if (!ruid && current->fsuid == 0 && current->uid != 0) { @@ -386,9 +426,10 @@ retry: goto retry; } PRINTK("NFS reply read failed = %d\n", status); + status = -nfs_stat_to_errno(status); } nfs_rpc_free(p0); - return (status == NFS_OK) ? len : -nfs_stat_to_errno(status); + return status; } int nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle, @@ -408,15 +449,16 @@ retry: *p++ = htonl(offset); *p++ = htonl(count); /* traditional, could be any value */ p = xdr_encode_data(p, data, count); - if ((status = nfs_rpc_call(server, p0, p)) < 0) { + if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) { nfs_rpc_free(p0); return status; } if (!(p = nfs_rpc_verify(p0))) - status = NFSERR_IO; + status = -errno_NFSERR_IO; else if ((status = ntohl(*p++)) == NFS_OK) { p = xdr_decode_fattr(p, fattr); PRINTK("NFS reply write\n"); + /* status = 0; */ } else { if (!ruid && current->fsuid == 0 && current->uid != 0) { @@ -424,9 +466,10 @@ retry: goto retry; } PRINTK("NFS reply write failed = %d\n", status); + status = -nfs_stat_to_errno(status); } nfs_rpc_free(p0); - return -nfs_stat_to_errno(status); + return status; } int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir, @@ -445,16 +488,17 @@ retry: p = xdr_encode_fhandle(p, dir); p = xdr_encode_string(p, name); p = xdr_encode_sattr(p, sattr); - if ((status = nfs_rpc_call(server, p0, p)) < 0) { + if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) { nfs_rpc_free(p0); return status; } if (!(p = nfs_rpc_verify(p0))) - status = NFSERR_IO; + status = -errno_NFSERR_IO; else if ((status = ntohl(*p++)) == NFS_OK) { p = xdr_decode_fhandle(p, fhandle); p = xdr_decode_fattr(p, fattr); PRINTK("NFS reply create\n"); + /* status = 0; */ } else { if (!ruid && current->fsuid == 0 && current->uid != 0) { @@ -462,9 +506,10 @@ retry: goto retry; } PRINTK("NFS reply create failed = %d\n", status); + status = -nfs_stat_to_errno(status); } nfs_rpc_free(p0); - return -nfs_stat_to_errno(status); + return status; } int nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir, const char *name) @@ -480,14 +525,15 @@ retry: p = nfs_rpc_header(p0, NFSPROC_REMOVE, ruid); p = xdr_encode_fhandle(p, dir); p = xdr_encode_string(p, name); - if ((status = nfs_rpc_call(server, p0, p)) < 0) { + if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) { nfs_rpc_free(p0); return status; } if (!(p = nfs_rpc_verify(p0))) - status = NFSERR_IO; + status = -errno_NFSERR_IO; else if ((status = ntohl(*p++)) == NFS_OK) { PRINTK("NFS reply remove\n"); + /* status = 0; */ } else { if (!ruid && current->fsuid == 0 && current->uid != 0) { @@ -495,9 +541,10 @@ retry: goto retry; } PRINTK("NFS reply remove failed = %d\n", status); + status = -nfs_stat_to_errno(status); } nfs_rpc_free(p0); - return -nfs_stat_to_errno(status); + return status; } int nfs_proc_rename(struct nfs_server *server, @@ -517,14 +564,15 @@ retry: p = xdr_encode_string(p, old_name); p = xdr_encode_fhandle(p, new_dir); p = xdr_encode_string(p, new_name); - if ((status = nfs_rpc_call(server, p0, p)) < 0) { + if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) { nfs_rpc_free(p0); return status; } if (!(p = nfs_rpc_verify(p0))) - status = NFSERR_IO; + status = -errno_NFSERR_IO; else if ((status = ntohl(*p++)) == NFS_OK) { PRINTK("NFS reply rename\n"); + /* status = 0; */ } else { if (!ruid && current->fsuid == 0 && current->uid != 0) { @@ -532,9 +580,10 @@ retry: goto retry; } PRINTK("NFS reply rename failed = %d\n", status); + status = -nfs_stat_to_errno(status); } nfs_rpc_free(p0); - return -nfs_stat_to_errno(status); + return status; } int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle, @@ -552,14 +601,15 @@ retry: p = xdr_encode_fhandle(p, fhandle); p = xdr_encode_fhandle(p, dir); p = xdr_encode_string(p, name); - if ((status = nfs_rpc_call(server, p0, p)) < 0) { + if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) { nfs_rpc_free(p0); return status; } if (!(p = nfs_rpc_verify(p0))) - status = NFSERR_IO; + status = -errno_NFSERR_IO; else if ((status = ntohl(*p++)) == NFS_OK) { PRINTK("NFS reply link\n"); + /* status = 0; */ } else { if (!ruid && current->fsuid == 0 && current->uid != 0) { @@ -567,9 +617,10 @@ retry: goto retry; } PRINTK("NFS reply link failed = %d\n", status); + status = -nfs_stat_to_errno(status); } nfs_rpc_free(p0); - return -nfs_stat_to_errno(status); + return status; } int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir, @@ -588,14 +639,15 @@ retry: p = xdr_encode_string(p, name); p = xdr_encode_string(p, path); p = xdr_encode_sattr(p, sattr); - if ((status = nfs_rpc_call(server, p0, p)) < 0) { + if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) { nfs_rpc_free(p0); return status; } if (!(p = nfs_rpc_verify(p0))) - status = NFSERR_IO; + status = -errno_NFSERR_IO; else if ((status = ntohl(*p++)) == NFS_OK) { PRINTK("NFS reply symlink\n"); + /* status = 0; */ } else { if (!ruid && current->fsuid == 0 && current->uid != 0) { @@ -603,9 +655,10 @@ retry: goto retry; } PRINTK("NFS reply symlink failed = %d\n", status); + status = -nfs_stat_to_errno(status); } nfs_rpc_free(p0); - return -nfs_stat_to_errno(status); + return status; } int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir, @@ -624,16 +677,17 @@ retry: p = xdr_encode_fhandle(p, dir); p = xdr_encode_string(p, name); p = xdr_encode_sattr(p, sattr); - if ((status = nfs_rpc_call(server, p0, p)) < 0) { + if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) { nfs_rpc_free(p0); return status; } if (!(p = nfs_rpc_verify(p0))) - status = NFSERR_IO; + status = -errno_NFSERR_IO; else if ((status = ntohl(*p++)) == NFS_OK) { p = xdr_decode_fhandle(p, fhandle); p = xdr_decode_fattr(p, fattr); PRINTK("NFS reply mkdir\n"); + /* status = 0; */ } else { if (!ruid && current->fsuid == 0 && current->uid != 0) { @@ -641,9 +695,10 @@ retry: goto retry; } PRINTK("NFS reply mkdir failed = %d\n", status); + status = -nfs_stat_to_errno(status); } nfs_rpc_free(p0); - return -nfs_stat_to_errno(status); + return status; } int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir, const char *name) @@ -659,14 +714,15 @@ retry: p = nfs_rpc_header(p0, NFSPROC_RMDIR, ruid); p = xdr_encode_fhandle(p, dir); p = xdr_encode_string(p, name); - if ((status = nfs_rpc_call(server, p0, p)) < 0) { + if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) { nfs_rpc_free(p0); return status; } if (!(p = nfs_rpc_verify(p0))) - status = NFSERR_IO; + status = -errno_NFSERR_IO; else if ((status = ntohl(*p++)) == NFS_OK) { PRINTK("NFS reply rmdir\n"); + /* status = 0; */ } else { if (!ruid && current->fsuid == 0 && current->uid != 0) { @@ -674,9 +730,10 @@ retry: goto retry; } PRINTK("NFS reply rmdir failed = %d\n", status); + status = -nfs_stat_to_errno(status); } nfs_rpc_free(p0); - return -nfs_stat_to_errno(status); + return status; } int nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle, @@ -685,7 +742,7 @@ int nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle, int *p, *p0; int status; int ruid = 0; - int i = 0; /* = 0 is for gcc */ + int i; int size; int eof; @@ -698,12 +755,12 @@ retry: p = xdr_encode_fhandle(p, fhandle); *p++ = htonl(cookie); *p++ = htonl(size); - if ((status = nfs_rpc_call(server, p0, p)) < 0) { + if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) { nfs_rpc_free(p0); return status; } if (!(p = nfs_rpc_verify(p0))) - status = NFSERR_IO; + status = -errno_NFSERR_IO; else if ((status = ntohl(*p++)) == NFS_OK) { for (i = 0; i < count && *p++; i++) { if (!(p = xdr_decode_entry(p, entry++))) @@ -711,7 +768,7 @@ retry: } if (!p) { printk("nfs_proc_readdir: giant filename\n"); - status = NFSERR_IO; + status = -errno_NFSERR_IO; } else { eof = (i == count && !*p++ && *p++) @@ -720,6 +777,7 @@ retry: entry[-1].eof = 1; PRINTK("NFS reply readdir %d %s\n", i, eof ? "eof" : ""); + status = i; } } else { @@ -728,9 +786,10 @@ retry: goto retry; } PRINTK("NFS reply readdir failed = %d\n", status); + status = -nfs_stat_to_errno(status); } nfs_rpc_free(p0); - return (status == NFS_OK) ? i : -nfs_stat_to_errno(status); + return status; } int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, @@ -746,15 +805,16 @@ int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, retry: p = nfs_rpc_header(p0, NFSPROC_STATFS, ruid); p = xdr_encode_fhandle(p, fhandle); - if ((status = nfs_rpc_call(server, p0, p)) < 0) { + if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) { nfs_rpc_free(p0); return status; } if (!(p = nfs_rpc_verify(p0))) - status = NFSERR_IO; + status = -errno_NFSERR_IO; else if ((status = ntohl(*p++)) == NFS_OK) { p = xdr_decode_fsinfo(p, res); PRINTK("NFS reply statfs\n"); + /* status = 0; */ } else { if (!ruid && current->fsuid == 0 && current->uid != 0) { @@ -762,9 +822,10 @@ retry: goto retry; } PRINTK("NFS reply statfs failed = %d\n", status); + status = -nfs_stat_to_errno(status); } nfs_rpc_free(p0); - return -nfs_stat_to_errno(status); + return status; } /* @@ -828,7 +889,7 @@ static int *nfs_rpc_verify(int *p) printk("nfs_rpc_verify: giant auth size\n"); return NULL; } - p += (n + 3) >> 2; + p += QUADLEN(n); if ((n = ntohl(*p++)) != RPC_SUCCESS) { printk("nfs_rpc_verify: RPC call failed: %d\n", n); return NULL; @@ -841,10 +902,6 @@ static int *nfs_rpc_verify(int *p) * the local errno values which may not be the same. */ -#ifndef EDQUOT -#define EDQUOT ENOSPC -#endif - static struct { int stat; int errno; @@ -852,7 +909,7 @@ static struct { { NFS_OK, 0 }, { NFSERR_PERM, EPERM }, { NFSERR_NOENT, ENOENT }, - { NFSERR_IO, EIO }, + { NFSERR_IO, errno_NFSERR_IO }, { NFSERR_NXIO, ENXIO }, { NFSERR_ACCES, EACCES }, { NFSERR_EXIST, EEXIST }, diff --git a/fs/nfs/sock.c b/fs/nfs/sock.c index d47635e6fd4a..1a1dc5486cee 100644 --- a/fs/nfs/sock.c +++ b/fs/nfs/sock.c @@ -11,6 +11,11 @@ * * An xid mismatch no longer causes the request to be trashed. * + * Peter Eriksson - incorrect XID used to confuse Linux + * Florian La Roche - use the correct max size, if reading a packet and + * also verify, if the whole packet has been read... + * more checks should be done in proc.c... + * */ #include @@ -44,7 +49,7 @@ extern struct socket *socki_lookup(struct inode *inode); * to the server socket. */ -static int do_nfs_rpc_call(struct nfs_server *server, int *start, int *end) +static int do_nfs_rpc_call(struct nfs_server *server, int *start, int *end, int size) { struct file *file; struct inode *inode; @@ -192,26 +197,23 @@ static int do_nfs_rpc_call(struct nfs_server *server, int *start, int *end) #if 0 printk("nfs_rpc_call: XID mismatch\n"); #endif + goto re_select; } /* JEJB/JSP 2/7/94 * * we have the correct xid, so read into the correct place and * return it * - * Here we need to know the size given to alloc, server->wsize for - * writes or server->rsize for reads. In practice these are the - * same. - * - * If they are not the same then a reply to a write request will be - * a small acknowledgment, so even if wsize < rsize we should never - * cause data to be written past the end of the buffer (unless some - * brain damaged implementation sends out a large write acknowledge). - * - * FIXME: I should really know how big a packet was alloc'd -- - * should pass it to do_nfs_rpc. */ + */ result=sock->ops->recvfrom(sock, (void *)start, - server->rsize + NFS_SLACK_SPACE, 1, 0, NULL, + size + 1024, 1, 0, NULL, + /* Here is NFS_SLACK_SPACE..., hack */ &addrlen); + if (result < addrlen) { + printk("NFS: just caught a too small read memory size..., email to NET channel\n"); + printk("NFS: result=%d,addrlen=%d\n", result, addrlen); + result = -EIO; + } current->blocked = old_mask; set_fs(fs); return result; @@ -223,14 +225,14 @@ static int do_nfs_rpc_call(struct nfs_server *server, int *start, int *end) * RPC replies. */ -int nfs_rpc_call(struct nfs_server *server, int *start, int *end) +int nfs_rpc_call(struct nfs_server *server, int *start, int *end, int size) { int result; while (server->lock) sleep_on(&server->wait); server->lock = 1; - result = do_nfs_rpc_call(server, start, end); + result = do_nfs_rpc_call(server, start, end, size); server->lock = 0; wake_up(&server->wait); return result; diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c index 9527b7f9ac26..c7f80e2898a2 100644 --- a/fs/nfs/symlink.c +++ b/fs/nfs/symlink.c @@ -3,6 +3,8 @@ * * Copyright (C) 1992 Rick Sladkey * + * Optimization changes Copyright (C) 1994 Florian La Roche + * * nfs symlink handling code */ @@ -14,6 +16,7 @@ #include #include #include +#include static int nfs_readlink(struct inode *, char *, int); static int nfs_follow_link(struct inode *, struct inode *, int, int, @@ -43,8 +46,9 @@ struct inode_operations nfs_symlink_inode_operations = { static int nfs_follow_link(struct inode *dir, struct inode *inode, int flag, int mode, struct inode **res_inode) { - int error; - char *res; + int error, *mem; + unsigned int len; + char *res, *res2; *res_inode = NULL; if (!dir) { @@ -65,27 +69,33 @@ static int nfs_follow_link(struct inode *dir, struct inode *inode, iput(dir); return -ELOOP; } - res = (char *) kmalloc(NFS_MAXPATHLEN + 1, GFP_KERNEL); - error = nfs_proc_readlink(NFS_SERVER(inode), NFS_FH(inode), res); + error = nfs_proc_readlink(NFS_SERVER(inode), NFS_FH(inode), &mem, + &res, &len, NFS_MAXPATHLEN); + if ((res2 = (char *) kmalloc(NFS_MAXPATHLEN + 1, GFP_KERNEL)) == NULL) { + printk("NFS: no memory in nfs_follow_link\n"); + error = -EIO; + } if (error) { iput(inode); iput(dir); - kfree_s(res, NFS_MAXPATHLEN + 1); + kfree(mem); return error; } + memcpy(res2, res, len); + res2[len] = '\0'; + kfree(mem); iput(inode); current->link_count++; - error = open_namei(res, flag, mode, res_inode, dir); + error = open_namei(res2, flag, mode, res_inode, dir); current->link_count--; - kfree_s(res, NFS_MAXPATHLEN + 1); + kfree_s(res2, NFS_MAXPATHLEN + 1); return error; } static int nfs_readlink(struct inode *inode, char *buffer, int buflen) { - int i; - char c; - int error; + int error, *mem; + unsigned int len; char *res; if (!S_ISLNK(inode->i_mode)) { @@ -94,15 +104,14 @@ static int nfs_readlink(struct inode *inode, char *buffer, int buflen) } if (buflen > NFS_MAXPATHLEN) buflen = NFS_MAXPATHLEN; - res = (char *) kmalloc(buflen + 1, GFP_KERNEL); - error = nfs_proc_readlink(NFS_SERVER(inode), NFS_FH(inode), res); + error = nfs_proc_readlink(NFS_SERVER(inode), NFS_FH(inode), &mem, + &res, &len, buflen); iput(inode); - if (error) { - kfree_s(res, buflen + 1); - return error; + if (! error) { + memcpy_tofs(buffer, res, len); + put_fs_byte('\0', buffer + len); + error = len; } - for (i = 0; i < buflen && (c = res[i]); i++) - put_fs_byte(c,buffer++); - kfree_s(res, buflen + 1); - return i; + kfree(mem); + return error; } diff --git a/fs/super.c b/fs/super.c index eb3f93cf38d9..35c58e06755a 100644 --- a/fs/super.c +++ b/fs/super.c @@ -20,14 +20,13 @@ #include #include - +#include extern struct file_operations * get_blkfops(unsigned int); extern struct file_operations * get_chrfops(unsigned int); extern void wait_for_keypress(void); extern void fcntl_init_locks(void); -extern int floppy_grab_irq_and_dma(void); extern int root_mountflags; @@ -296,23 +295,15 @@ static struct super_block * read_super(dev_t dev,char *name,int flags, * filesystems which don't use real block-devices. -- jrs */ -static char unnamed_dev_in_use[256]; +static char unnamed_dev_in_use[256/8] = { 0, }; static dev_t get_unnamed_dev(void) { - static int first_use = 0; int i; - if (first_use == 0) { - first_use = 1; - memset(unnamed_dev_in_use, 0, sizeof(unnamed_dev_in_use)); - unnamed_dev_in_use[0] = 1; /* minor 0 (nodev) is special */ - } - for (i = 0; i < sizeof unnamed_dev_in_use/sizeof unnamed_dev_in_use[0]; i++) { - if (!unnamed_dev_in_use[i]) { - unnamed_dev_in_use[i] = 1; + for (i = 1; i < 256; i++) { + if (!set_bit(i,unnamed_dev_in_use)) return (UNNAMED_MAJOR << 8) | i; - } } return 0; } @@ -321,12 +312,11 @@ static void put_unnamed_dev(dev_t dev) { if (!dev) return; - if (!unnamed_dev_in_use[dev]) { - printk("VFS: put_unnamed_dev: freeing unused device %d/%d\n", - MAJOR(dev), MINOR(dev)); + if (MAJOR(dev) == UNNAMED_MAJOR && + clear_bit(MINOR(dev), unnamed_dev_in_use)) return; - } - unnamed_dev_in_use[dev] = 0; + printk("VFS: put_unnamed_dev: freeing unused device %d/%d\n", + MAJOR(dev), MINOR(dev)); } static int do_umount(dev_t dev) @@ -645,18 +635,35 @@ void mount_root(void) { struct file_system_type * fs_type; struct super_block * sb; - struct inode * inode; + struct inode * inode, d_inode; + struct file filp; + int retval; memset(super_blocks, 0, sizeof(super_blocks)); fcntl_init_locks(); if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) { printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER\n"); wait_for_keypress(); - /* ugly, ugly */ - if (floppy_grab_irq_and_dma()) - printk("Unable to grab floppy IRQ/DMA for mounting root floppy\n"); } + + memset(&filp, 0, sizeof(filp)); + memset(&d_inode, 0, sizeof(d_inode)); + d_inode.i_rdev = ROOT_DEV; + filp.f_inode = &d_inode; + if ( root_mountflags & MS_RDONLY) + filp.f_mode = 1; /* read only */ + else + filp.f_mode = 3; /* read write */ + retval = blkdev_open(&d_inode, &filp); + if(retval == -EROFS){ + root_mountflags |= MS_RDONLY; + filp.f_mode = 1; + retval = blkdev_open(&d_inode, &filp); + } + for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) { + if(retval) + break; if (!fs_type->requires_dev) continue; sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,NULL,1); diff --git a/fs/sysv/README b/fs/sysv/README index 4b0264a8c39f..5b449cb7c6c8 100644 --- a/fs/sysv/README +++ b/fs/sysv/README @@ -4,7 +4,7 @@ It implements all of - SystemV/386 FS, - Coherent FS. -This is version beta 2. +This is version beta 3. To install: * Answer the 'System V and Coherent filesystem support' question with 'y' diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index d4f56a8271b8..07ef17030b0d 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -306,6 +306,10 @@ struct super_block *sysv_read_super(struct super_block *sb,void *data, for (i = 0; i < sizeof(offsets)/sizeof(offsets[0]); i++) if ((bh = bread(dev, offsets[i], BLOCK_SIZE)) != NULL) { /* Try to recognize SystemV superblock */ + if ((found = detect_sysv4(sb,bh)) != NULL) { + sb->sv_block_base = offsets[i]; + goto ok; + } if ((found = detect_sysv2(sb,bh)) != NULL) { sb->sv_block_base = offsets[i]; goto ok; diff --git a/include/linux/fd.h b/include/linux/fd.h index 7248805e0c34..76b9c64796df 100644 --- a/include/linux/fd.h +++ b/include/linux/fd.h @@ -228,10 +228,12 @@ struct floppy_raw_cmd { /* flags */ #define FD_RAW_READ 1 #define FD_RAW_WRITE 2 +#define FD_RAW_NO_MOTOR 4 +#define FD_RAW_DISK_CHANGE 4 #define FD_RAW_INTR 8 #define FD_RAW_SPIN 16 +#define FD_RAW_NO_MOTOR_AFTER 32 #define FD_RAW_NEED_DISK 64 #define FD_RAW_NEED_SEEK 128 -#define FD_RAW_USER_SUPPLIED 256 #endif diff --git a/include/linux/fdreg.h b/include/linux/fdreg.h index ff376fedb50b..245647bbf11e 100644 --- a/include/linux/fdreg.h +++ b/include/linux/fdreg.h @@ -89,6 +89,8 @@ #define FD_READID 0xEA /* prints the header of a sector */ #define FD_UNLOCK 0x14 /* Fifo config unlock */ #define FD_LOCK 0x94 /* Fifo config lock */ +#define FD_RSEEK_OUT 0x8f /* seek out (i.e. to lower tracks) */ +#define FD_RSEEK_IN 0xcf /* seek in (i.e. to higher tracks) */ /* DMA commands */ #define DMA_READ 0x46 diff --git a/include/linux/hdreg.h b/include/linux/hdreg.h index f4b448bc9e2f..e401ac625ec1 100644 --- a/include/linux/hdreg.h +++ b/include/linux/hdreg.h @@ -79,7 +79,7 @@ struct hd_geometry { struct hd_driveid { unsigned short config; /* lots of obsolete bit flags */ unsigned short cyls; /* "physical" cyls */ - unsigned short reserved0; /* reserved */ + unsigned short reserved2; /* reserved (word 2) */ unsigned short heads; /* "physical" heads */ unsigned short track_bytes; /* unformatted bytes per track */ unsigned short sector_bytes; /* unformatted bytes per sector */ @@ -97,13 +97,13 @@ struct hd_driveid { unsigned char vendor3; /* vendor unique */ unsigned short dword_io; /* 0=not_implemented; 1=implemented */ unsigned char vendor4; /* vendor unique */ - unsigned char capability; /* bit0:DMA, bit1:LBA */ - unsigned short reserved1; /* reserved */ + unsigned char capability; /* bits 0:DMA 1:LBA 2:IORDYsw 3:IORDYsup*/ + unsigned short reserved50; /* reserved (word 50) */ unsigned char vendor5; /* vendor unique */ unsigned char tPIO; /* 0=slow, 1=medium, 2=fast */ unsigned char vendor6; /* vendor unique */ unsigned char tDMA; /* 0=slow, 1=medium, 2=fast */ - unsigned short cur_valid; /* when (bit0==1) use logical geom */ + unsigned short field_valid; /* bits 0:cur_ok 1:eide_ok */ unsigned short cur_cyls; /* logical cylinders */ unsigned short cur_heads; /* logical heads */ unsigned short cur_sectors; /* logical sectors per track */ @@ -114,7 +114,14 @@ struct hd_driveid { unsigned int lba_capacity; /* total number of sectors */ unsigned short dma_1word; /* single-word dma info */ unsigned short dma_mword; /* multiple-word dma info */ - /* unsigned short reserved2[64];*/ /* reserved */ - /* unsigned short vendor7 [32];*/ /* vendor unique */ - /* unsigned short reserved3[96];*/ /* reserved */ + unsigned short eide_pio_modes; /* bits 0:mode3 1:mode4 */ + unsigned short eide_dma_min; /* min mword dma cycle time (ns) */ + unsigned short eide_dma_time; /* recommended mword dma cycle time (ns) */ + unsigned short eide_pio; /* min cycle time (ns), no IORDY */ + unsigned short eide_pio_iordy; /* min cycle time (ns), with IORDY */ + unsigned short reserved69; /* reserved (word 69) */ + unsigned short reserved70; /* reserved (word 70) */ + /* unsigned short reservedxx[57];*/ /* reserved (words 71-127) */ + /* unsigned short vendor7 [32];*/ /* vendor unique (words 128-159) */ + /* unsigned short reservedyy[96];*/ /* reserved (words 160-255) */ }; diff --git a/include/linux/lp.h b/include/linux/lp.h index de3061e2e097..b8a1c03fca64 100644 --- a/include/linux/lp.h +++ b/include/linux/lp.h @@ -90,19 +90,6 @@ struct lp_struct { char *lp_buffer; }; -/* the BIOS manuals say there can be up to 4 lpt devices - * but I have not seen a board where the 4th address is listed - * if you have different hardware change the table below - * please let me know if you have different equipment - * if you have more than 3 printers, remember to increase LP_NO - */ -struct lp_struct lp_table[] = { - { 0x3bc, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, }, - { 0x378, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, }, - { 0x278, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, }, -}; -#define LP_NO 3 - /* * bit defines for 8255 status port * base + 1 diff --git a/include/linux/ncp.h b/include/linux/ncp.h deleted file mode 100644 index bd6daf29dbbc..000000000000 --- a/include/linux/ncp.h +++ /dev/null @@ -1,106 +0,0 @@ -#ifndef _LINUX_NCP_H_ -#define _LINUX_NCP_H_ - -#define NCP_OPEN 0x1111 -#define NCP_CLOSE 0x5555 -#define NCP_REQUEST 0x2222 -#define NCP_REPLY 0x3333 - -struct ncp_request -{ - unsigned short p_type __attribute__ ((packed)); - unsigned char seq __attribute__ ((packed)); - unsigned char c_low __attribute__ ((packed)); - unsigned char task __attribute__ ((packed)); - unsigned char c_high __attribute__ ((packed)); - unsigned char func __attribute__ ((packed)); -}; - -struct ncp_request_sf -{ - unsigned short p_type __attribute__ ((packed)); - unsigned char seq __attribute__ ((packed)); - unsigned char c_low __attribute__ ((packed)); - unsigned char task __attribute__ ((packed)); - unsigned char c_high __attribute__ ((packed)); - unsigned char func __attribute__ ((packed)); - unsigned short s_len __attribute__ ((packed)); - unsigned char s_func __attribute__ ((packed)); -}; - -struct ncp_reply -{ - unsigned short p_type __attribute__ ((packed)); - unsigned char seq __attribute__ ((packed)); - unsigned char c_low __attribute__ ((packed)); - unsigned char task __attribute__ ((packed)); - unsigned char c_high __attribute__ ((packed)); - unsigned char f_stat __attribute__ ((packed)); - unsigned char c_stat __attribute__ ((packed)); -}; - -#define OTYPE_USER 0x0001 -#define OTYPE_GROUP 0x0002 -#define OTYPE_PQUEUE 0x0003 -#define OTYPE_FSERVER 0x0004 -#define OTYPE_JSERVER 0x0005 -#define OTYPE_PSERVER 0x0007 -#define OTYPE_UNKNOWN_1 0x002E -#define OTYPE_ADV_PSERVER 0x0047 -#define OTYPE_AFSERVER 0x0107 -#define OTYPE_UNKNOWN_2 0x0143 -#define OTYPE_UNKNOWN_3 0x01F5 -#define OTYPE_UNKNOWN_4 0x023F - -#define LIMIT_OBJNAME 47 - -struct bind_obj -{ - unsigned long id __attribute__ ((packed)); - unsigned short type __attribute__ ((packed)); - char name[LIMIT_OBJNAME+1] __attribute__ ((packed)); -}; - -struct get_bind_obj -{ - unsigned short type __attribute__ ((packed)); - unsigned char n_len __attribute__ ((packed)); - char name[0] __attribute__ ((packed)); -}; - -struct scan_bind_obj -{ - unsigned long id __attribute__ ((packed)); - unsigned short type __attribute__ ((packed)); - unsigned char n_len __attribute__ ((packed)); - char name[0] __attribute__ ((packed)); -}; - -struct login_req -{ - unsigned char password[8] __attribute__ ((packed)); - unsigned short type __attribute__ ((packed)); - unsigned char n_len __attribute__ ((packed)); - char name[0] __attribute__ ((packed)); -}; - -struct ncp_time -{ - unsigned char year __attribute__ ((packed)); - unsigned char month __attribute__ ((packed)); - unsigned char day __attribute__ ((packed)); - unsigned char hours __attribute__ ((packed)); - unsigned char mins __attribute__ ((packed)); - unsigned char secs __attribute__ ((packed)); - unsigned char c_secs __attribute__ ((packed)); -}; - -struct login_info -{ - unsigned long id __attribute__ ((packed)); - unsigned short un1 __attribute__ ((packed)); - char name[LIMIT_OBJNAME+1] __attribute__ ((packed)); - struct ncp_time time __attribute__ ((packed)); -}; -#endif - diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index a0c103f6ccd9..66116a4e7f71 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -57,10 +57,11 @@ extern int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir, const char *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr); extern int nfs_proc_readlink(struct nfs_server *server, struct nfs_fh *fhandle, - char *res); + int **p0, char **string, unsigned int *len, + unsigned int maxlen); extern int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle, int offset, int count, char *data, - struct nfs_fattr *fattr); + struct nfs_fattr *fattr, int fs); extern int nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle, int offset, int count, char *data, struct nfs_fattr *fattr); @@ -88,7 +89,7 @@ extern int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, /* linux/fs/nfs/sock.c */ -extern int nfs_rpc_call(struct nfs_server *server, int *start, int *end); +extern int nfs_rpc_call(struct nfs_server *server, int *start, int *end, int size); /* linux/fs/nfs/inode.c */ diff --git a/include/linux/tty.h b/include/linux/tty.h index b5bc72cc31fc..e44c5e2cb85a 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -247,6 +247,7 @@ struct tty_struct { #define TTY_EXCLUSIVE 3 #define TTY_DEBUG 4 #define TTY_DO_WRITE_WAKEUP 5 +#define TTY_PUSH 6 #define TTY_WRITE_FLUSH(tty) tty_write_flush((tty)) diff --git a/kernel/bios32.c b/kernel/bios32.c index 6d3b97cbf0bc..f6806905c3d3 100644 --- a/kernel/bios32.c +++ b/kernel/bios32.c @@ -455,7 +455,15 @@ unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end) printk ("bios32_init : BIOS32 Service Directory entry at 0x%lx\n", bios32_entry); } else { printk ("bios32_init : multiple entries, mail drew@colorado.edu\n"); + /* + * Jeremy Fitzhardinge reports at least one PCI BIOS + * with two different service directories, and as both + * worked for him, we'll just mention the fact, and + * not actually disallow it.. + */ +#if 0 return memory_start; +#endif } } #ifdef CONFIG_PCI diff --git a/kernel/itimer.c b/kernel/itimer.c index 922029c25d2e..4d5fa0f67116 100644 --- a/kernel/itimer.c +++ b/kernel/itimer.c @@ -112,15 +112,24 @@ asmlinkage int sys_setitimer(int which, struct itimerval *value, struct itimerva int error; struct itimerval set_buffer, get_buffer; - if (!value) - memset((char *) &set_buffer, 0, sizeof(set_buffer)); - else + if (value) { + error = verify_area(VERIFY_READ, value, sizeof(*value)); + if (error) + return error; memcpy_fromfs(&set_buffer, value, sizeof(set_buffer)); + } else + memset((char *) &set_buffer, 0, sizeof(set_buffer)); + + if (ovalue) { + error = verify_area(VERIFY_WRITE, ovalue, sizeof(struct itimerval)); + if (error) + return error; + } + error = _setitimer(which, &set_buffer, ovalue ? &get_buffer : 0); if (error || !ovalue) return error; - error = verify_area(VERIFY_WRITE, ovalue, sizeof(struct itimerval)); - if (!error) - memcpy_tofs(ovalue, &get_buffer, sizeof(get_buffer)); + + memcpy_tofs(ovalue, &get_buffer, sizeof(get_buffer)); return error; } diff --git a/kernel/sched.c b/kernel/sched.c index c6ad52fb45ae..edc2cec95f6a 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -675,6 +676,16 @@ static void do_timer(struct pt_regs * regs) } #endif } + /* + * check the cpu time limit on the process. + */ + if ((current->rlim[RLIMIT_CPU].rlim_cur != RLIM_INFINITY) && + (((current->stime + current->utime) / HZ) >= current->rlim[RLIMIT_CPU].rlim_cur)) + send_sig(SIGXCPU, current, 1); + if ((current->rlim[RLIMIT_CPU].rlim_max != RLIM_INFINITY) && + (((current->stime + current->utime) / HZ) >= current->rlim[RLIMIT_CPU].rlim_max)) + send_sig(SIGKILL, current, 1); + if (current != task[0] && 0 > --current->counter) { current->counter = 0; need_resched = 1; diff --git a/kernel/sys.c b/kernel/sys.c index 3aac92a0e396..575228c479ab 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -697,12 +697,15 @@ asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim) asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim) { struct rlimit new_rlim, *old_rlim; + int err; if (resource >= RLIM_NLIMITS) return -EINVAL; + err = verify_area(VERIFY_READ, rlim, sizeof(*rlim)); + if (err) + return err; + memcpy_fromfs(&new_rlim, rlim, sizeof(*rlim)); old_rlim = current->rlim + resource; - new_rlim.rlim_cur = get_fs_long((unsigned long *) rlim); - new_rlim.rlim_max = get_fs_long(((unsigned long *) rlim)+1); if (((new_rlim.rlim_cur > old_rlim->rlim_max) || (new_rlim.rlim_max > old_rlim->rlim_max)) && !suser()) @@ -723,7 +726,6 @@ int getrusage(struct task_struct *p, int who, struct rusage *ru) { int error; struct rusage r; - unsigned long *lp, *lpend, *dest; error = verify_area(VERIFY_WRITE, ru, sizeof *ru); if (error) @@ -755,11 +757,7 @@ int getrusage(struct task_struct *p, int who, struct rusage *ru) r.ru_majflt = p->mm->maj_flt + p->mm->cmaj_flt; break; } - lp = (unsigned long *) &r; - lpend = (unsigned long *) (&r+1); - dest = (unsigned long *) ru; - for (; lp < lpend; lp++, dest++) - put_fs_long(*lp, dest); + memcpy_tofs(ru, &r, sizeof(r)); return 0; } diff --git a/kernel/sys_call.S b/kernel/sys_call.S deleted file mode 100644 index 5193d1149cb7..000000000000 --- a/kernel/sys_call.S +++ /dev/null @@ -1,545 +0,0 @@ -/* - * linux/kernel/sys_call.S - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -/* - * sys_call.S contains the system-call and fault low-level handling routines. - * This also contains the timer-interrupt handler, as well as all interrupts - * and faults that can result in a task-switch. - * - * NOTE: This code handles signal-recognition, which happens every time - * after a timer-interrupt and after each system call. - * - * I changed all the .align's to 4 (16 byte alignment), as that's faster - * on a 486. - * - * Stack layout in 'ret_from_system_call': - * ptrace needs to have all regs on the stack. - * if the order here is changed, it needs to be - * updated in fork.c:copy_process, signal.c:do_signal, - * ptrace.c and ptrace.h - * - * 0(%esp) - %ebx - * 4(%esp) - %ecx - * 8(%esp) - %edx - * C(%esp) - %esi - * 10(%esp) - %edi - * 14(%esp) - %ebp - * 18(%esp) - %eax - * 1C(%esp) - %ds - * 20(%esp) - %es - * 24(%esp) - %fs - * 28(%esp) - %gs - * 2C(%esp) - orig_eax - * 30(%esp) - %eip - * 34(%esp) - %cs - * 38(%esp) - %eflags - * 3C(%esp) - %oldesp - * 40(%esp) - %oldss - */ - -#include -#include - -EBX = 0x00 -ECX = 0x04 -EDX = 0x08 -ESI = 0x0C -EDI = 0x10 -EBP = 0x14 -EAX = 0x18 -DS = 0x1C -ES = 0x20 -FS = 0x24 -GS = 0x28 -ORIG_EAX = 0x2C -EIP = 0x30 -CS = 0x34 -EFLAGS = 0x38 -OLDESP = 0x3C -OLDSS = 0x40 - -CF_MASK = 0x00000001 -IF_MASK = 0x00000200 -NT_MASK = 0x00004000 -VM_MASK = 0x00020000 - -/* - * these are offsets into the task-struct. - */ -state = 0 -counter = 4 -priority = 8 -signal = 12 -blocked = 16 -flags = 20 -errno = 24 -dbgreg6 = 52 -dbgreg7 = 56 -exec_domain = 60 - -ENOSYS = 38 - -.globl _system_call,_lcall7 -.globl _device_not_available, _coprocessor_error -.globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op -.globl _double_fault,_coprocessor_segment_overrun -.globl _invalid_TSS,_segment_not_present,_stack_segment -.globl _general_protection,_reserved -.globl _alignment_check,_page_fault -.globl ret_from_sys_call, _sys_call_table - -#define SAVE_ALL \ - cld; \ - push %gs; \ - push %fs; \ - push %es; \ - push %ds; \ - pushl %eax; \ - pushl %ebp; \ - pushl %edi; \ - pushl %esi; \ - pushl %edx; \ - pushl %ecx; \ - pushl %ebx; \ - movl $(KERNEL_DS),%edx; \ - mov %dx,%ds; \ - mov %dx,%es; \ - movl $(USER_DS),%edx; \ - mov %dx,%fs; - -#define RESTORE_ALL \ - cmpw $(KERNEL_CS),CS(%esp); \ - je 1f; \ - movl _current,%eax; \ - movl dbgreg7(%eax),%ebx; \ - movl %ebx,%db7; \ -1: popl %ebx; \ - popl %ecx; \ - popl %edx; \ - popl %esi; \ - popl %edi; \ - popl %ebp; \ - popl %eax; \ - pop %ds; \ - pop %es; \ - pop %fs; \ - pop %gs; \ - addl $4,%esp; \ - iret - -.align 4 -_lcall7: - pushfl # We get a different stack layout with call gates, - pushl %eax # which has to be cleaned up later.. - SAVE_ALL - movl EIP(%esp),%eax # due to call gates, this is eflags, not eip.. - movl CS(%esp),%edx # this is eip.. - movl EFLAGS(%esp),%ecx # and this is cs.. - movl %eax,EFLAGS(%esp) # - movl %edx,EIP(%esp) # Now we move them to their "normal" places - movl %ecx,CS(%esp) # - movl %esp,%eax - movl _current,%edx - pushl %eax - movl exec_domain(%edx),%edx # Get the execution domain - movl 4(%edx),%edx # Get the lcall7 handler for the domain - call *%edx - popl %eax - jmp ret_from_sys_call - -.align 4 -handle_bottom_half: - pushfl - incl _intr_count - sti - call _do_bottom_half - popfl - decl _intr_count - jmp 9f -.align 4 -reschedule: - pushl $ret_from_sys_call - jmp _schedule -.align 4 -_system_call: - pushl %eax # save orig_eax - SAVE_ALL - movl $-ENOSYS,EAX(%esp) - cmpl $(NR_syscalls),%eax - jae ret_from_sys_call - movl _sys_call_table(,%eax,4),%eax - testl %eax,%eax - je ret_from_sys_call - movl _current,%ebx - andl $~CF_MASK,EFLAGS(%esp) # clear carry - assume no errors - movl $0,errno(%ebx) - movl %db6,%edx - movl %edx,dbgreg6(%ebx) # save current hardware debugging status - testb $0x20,flags(%ebx) # PF_TRACESYS - jne 1f - call *%eax - movl %eax,EAX(%esp) # save the return value - movl errno(%ebx),%edx - negl %edx - je ret_from_sys_call - movl %edx,EAX(%esp) - orl $(CF_MASK),EFLAGS(%esp) # set carry to indicate error - jmp ret_from_sys_call -.align 4 -1: call _syscall_trace - movl ORIG_EAX(%esp),%eax - call _sys_call_table(,%eax,4) - movl %eax,EAX(%esp) # save the return value - movl _current,%eax - movl errno(%eax),%edx - negl %edx - je 1f - movl %edx,EAX(%esp) - orl $(CF_MASK),EFLAGS(%esp) # set carry to indicate error -1: call _syscall_trace - - .align 4,0x90 -ret_from_sys_call: - cmpl $0,_intr_count - jne 2f -9: movl _bh_mask,%eax - andl _bh_active,%eax - jne handle_bottom_half - movl EFLAGS(%esp),%eax # check VM86 flag: CS/SS are - testl $(VM_MASK),%eax # different then - jne 1f - cmpw $(KERNEL_CS),CS(%esp) # was old code segment supervisor ? - je 2f -1: sti - orl $(IF_MASK),%eax # these just try to make sure - andl $~NT_MASK,%eax # the program doesn't do anything - movl %eax,EFLAGS(%esp) # stupid - cmpl $0,_need_resched - jne reschedule - movl _current,%eax - cmpl _task,%eax # task[0] cannot have signals - je 2f - cmpl $0,state(%eax) # state - jne reschedule - cmpl $0,counter(%eax) # counter - je reschedule - movl blocked(%eax),%ecx - movl %ecx,%ebx # save blocked in %ebx for signal handling - notl %ecx - andl signal(%eax),%ecx - jne signal_return -2: RESTORE_ALL -.align 4 -signal_return: - movl %esp,%ecx - pushl %ecx - testl $(VM_MASK),EFLAGS(%ecx) - jne v86_signal_return - pushl %ebx - call _do_signal - popl %ebx - popl %ebx - RESTORE_ALL -.align 4 -v86_signal_return: - call _save_v86_state - movl %eax,%esp - pushl %eax - pushl %ebx - call _do_signal - popl %ebx - popl %ebx - RESTORE_ALL - -.align 4 -_divide_error: - pushl $0 # no error code - pushl $_do_divide_error -.align 4,0x90 -error_code: - push %fs - push %es - push %ds - pushl %eax - pushl %ebp - pushl %edi - pushl %esi - pushl %edx - pushl %ecx - pushl %ebx - movl $0,%eax - movl %eax,%db7 # disable hardware debugging... - cld - movl $-1, %eax - xchgl %eax, ORIG_EAX(%esp) # orig_eax (get the error code. ) - xorl %ebx,%ebx # zero ebx - mov %gs,%bx # get the lower order bits of gs - xchgl %ebx, GS(%esp) # get the address and save gs. - pushl %eax # push the error code - lea 4(%esp),%edx - pushl %edx - movl $(KERNEL_DS),%edx - mov %dx,%ds - mov %dx,%es - movl $(USER_DS),%edx - mov %dx,%fs - pushl %eax - movl _current,%eax - movl %db6,%edx - movl %edx,dbgreg6(%eax) # save current hardware debugging status - popl %eax - call *%ebx - addl $8,%esp - jmp ret_from_sys_call - -.align 4 -_coprocessor_error: - pushl $0 - pushl $_do_coprocessor_error - jmp error_code - -.align 4 -_device_not_available: - pushl $-1 # mark this as an int - SAVE_ALL - pushl $ret_from_sys_call - movl %cr0,%eax - testl $0x4,%eax # EM (math emulation bit) - je _math_state_restore - pushl $0 # temporary storage for ORIG_EIP - call _math_emulate - addl $4,%esp - ret - -.align 4 -_debug: - pushl $0 - pushl $_do_debug - jmp error_code - -.align 4 -_nmi: - pushl $0 - pushl $_do_nmi - jmp error_code - -.align 4 -_int3: - pushl $0 - pushl $_do_int3 - jmp error_code - -.align 4 -_overflow: - pushl $0 - pushl $_do_overflow - jmp error_code - -.align 4 -_bounds: - pushl $0 - pushl $_do_bounds - jmp error_code - -.align 4 -_invalid_op: - pushl $0 - pushl $_do_invalid_op - jmp error_code - -.align 4 -_coprocessor_segment_overrun: - pushl $0 - pushl $_do_coprocessor_segment_overrun - jmp error_code - -.align 4 -_reserved: - pushl $0 - pushl $_do_reserved - jmp error_code - -.align 4 -_double_fault: - pushl $_do_double_fault - jmp error_code - -.align 4 -_invalid_TSS: - pushl $_do_invalid_TSS - jmp error_code - -.align 4 -_segment_not_present: - pushl $_do_segment_not_present - jmp error_code - -.align 4 -_stack_segment: - pushl $_do_stack_segment - jmp error_code - -.align 4 -_general_protection: - pushl $_do_general_protection - jmp error_code - -.align 4 -_alignment_check: - pushl $_do_alignment_check - jmp error_code - -.align 4 -_page_fault: - pushl $_do_page_fault - jmp error_code - -.data -.align 4 -_sys_call_table: - .long _sys_setup /* 0 */ - .long _sys_exit - .long _sys_fork - .long _sys_read - .long _sys_write - .long _sys_open /* 5 */ - .long _sys_close - .long _sys_waitpid - .long _sys_creat - .long _sys_link - .long _sys_unlink /* 10 */ - .long _sys_execve - .long _sys_chdir - .long _sys_time - .long _sys_mknod - .long _sys_chmod /* 15 */ - .long _sys_chown - .long _sys_break - .long _sys_stat - .long _sys_lseek - .long _sys_getpid /* 20 */ - .long _sys_mount - .long _sys_umount - .long _sys_setuid - .long _sys_getuid - .long _sys_stime /* 25 */ - .long _sys_ptrace - .long _sys_alarm - .long _sys_fstat - .long _sys_pause - .long _sys_utime /* 30 */ - .long _sys_stty - .long _sys_gtty - .long _sys_access - .long _sys_nice - .long _sys_ftime /* 35 */ - .long _sys_sync - .long _sys_kill - .long _sys_rename - .long _sys_mkdir - .long _sys_rmdir /* 40 */ - .long _sys_dup - .long _sys_pipe - .long _sys_times - .long _sys_prof - .long _sys_brk /* 45 */ - .long _sys_setgid - .long _sys_getgid - .long _sys_signal - .long _sys_geteuid - .long _sys_getegid /* 50 */ - .long _sys_acct - .long _sys_phys - .long _sys_lock - .long _sys_ioctl - .long _sys_fcntl /* 55 */ - .long _sys_mpx - .long _sys_setpgid - .long _sys_ulimit - .long _sys_olduname - .long _sys_umask /* 60 */ - .long _sys_chroot - .long _sys_ustat - .long _sys_dup2 - .long _sys_getppid - .long _sys_getpgrp /* 65 */ - .long _sys_setsid - .long _sys_sigaction - .long _sys_sgetmask - .long _sys_ssetmask - .long _sys_setreuid /* 70 */ - .long _sys_setregid - .long _sys_sigsuspend - .long _sys_sigpending - .long _sys_sethostname - .long _sys_setrlimit /* 75 */ - .long _sys_getrlimit - .long _sys_getrusage - .long _sys_gettimeofday - .long _sys_settimeofday - .long _sys_getgroups /* 80 */ - .long _sys_setgroups - .long _sys_select - .long _sys_symlink - .long _sys_lstat - .long _sys_readlink /* 85 */ - .long _sys_uselib - .long _sys_swapon - .long _sys_reboot - .long _sys_readdir - .long _sys_mmap /* 90 */ - .long _sys_munmap - .long _sys_truncate - .long _sys_ftruncate - .long _sys_fchmod - .long _sys_fchown /* 95 */ - .long _sys_getpriority - .long _sys_setpriority - .long _sys_profil - .long _sys_statfs - .long _sys_fstatfs /* 100 */ - .long _sys_ioperm - .long _sys_socketcall - .long _sys_syslog - .long _sys_setitimer - .long _sys_getitimer /* 105 */ - .long _sys_newstat - .long _sys_newlstat - .long _sys_newfstat - .long _sys_uname - .long _sys_iopl /* 110 */ - .long _sys_vhangup - .long _sys_idle - .long _sys_vm86 - .long _sys_wait4 - .long _sys_swapoff /* 115 */ - .long _sys_sysinfo - .long _sys_ipc - .long _sys_fsync - .long _sys_sigreturn - .long _sys_clone /* 120 */ - .long _sys_setdomainname - .long _sys_newuname - .long _sys_modify_ldt - .long _sys_adjtimex - .long _sys_mprotect /* 125 */ - .long _sys_sigprocmask - .long _sys_create_module - .long _sys_init_module - .long _sys_delete_module - .long _sys_get_kernel_syms /* 130 */ - .long _sys_quotactl - .long _sys_getpgid - .long _sys_fchdir - .long _sys_bdflush - .long _sys_sysfs /* 135 */ - .long _sys_personality - .long 0 /* for afs_syscall */ - .long _sys_setfsuid - .long _sys_setfsgid - .long _sys_llseek /* 140 */ - .space (NR_syscalls-139)*4 - .space (NR_syscalls-140)*4 diff --git a/kernel/time.c b/kernel/time.c index c80ac1f1a1d7..e290a36543a8 100644 --- a/kernel/time.c +++ b/kernel/time.c @@ -97,6 +97,7 @@ void time_init(void) if ((year += 1900) < 1970) year += 100; xtime.tv_sec = mktime(year, mon, day, hour, min, sec); + xtime.tv_usec = 0; } /* * The timezone where the local system is located. Used as a default by some @@ -118,12 +119,19 @@ asmlinkage int sys_time(long * tloc) return i; } -asmlinkage int sys_stime(long * tptr) +asmlinkage int sys_stime(unsigned long * tptr) { + int error; + unsigned long value; + if (!suser()) return -EPERM; + error = verify_area(VERIFY_READ, tptr, sizeof(*tptr)); + if (error) + return error; + value = get_fs_long(tptr); cli(); - xtime.tv_sec = get_fs_long((unsigned long *) tptr); + xtime.tv_sec = value; xtime.tv_usec = 0; time_status = TIME_BAD; time_maxerror = 0x70000000; @@ -266,12 +274,25 @@ inline static void warp_clock(void) asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz) { static int firsttime = 1; + struct timeval new_tv; + struct timezone new_tz; if (!suser()) return -EPERM; + if (tv) { + int error = verify_area(VERIFY_READ, tv, sizeof(*tv)); + if (error) + return error; + memcpy_fromfs(&new_tv, tv, sizeof(*tv)); + } if (tz) { - sys_tz.tz_minuteswest = get_fs_long((unsigned long *) tz); - sys_tz.tz_dsttime = get_fs_long(((unsigned long *) tz)+1); + int error = verify_area(VERIFY_READ, tz, sizeof(*tz)); + if (error) + return error; + memcpy_fromfs(&new_tz, tz, sizeof(*tz)); + } + if (tz) { + sys_tz = new_tz; if (firsttime) { firsttime = 0; if (!tv) @@ -279,11 +300,6 @@ asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz) } } if (tv) { - int sec, usec; - - sec = get_fs_long((unsigned long *)tv); - usec = get_fs_long(((unsigned long *)tv)+1); - cli(); /* This is revolting. We need to set the xtime.tv_usec * correctly. However, the value in this location is @@ -291,15 +307,14 @@ asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz) * Discover what correction gettimeofday * would have done, and then undo it! */ - usec -= do_gettimeoffset(); + new_tv.tv_usec -= do_gettimeoffset(); - if (usec < 0) - { - usec += 1000000; - sec--; + if (new_tv.tv_usec < 0) { + new_tv.tv_usec += 1000000; + new_tv.tv_sec--; } - xtime.tv_sec = sec; - xtime.tv_usec = usec; + + xtime = new_tv; time_status = TIME_BAD; time_maxerror = 0x70000000; time_esterror = 0x70000000; diff --git a/kernel/vsprintf.c b/kernel/vsprintf.c index 923005a15133..00748da06a0f 100644 --- a/kernel/vsprintf.c +++ b/kernel/vsprintf.c @@ -169,6 +169,7 @@ int vsprintf(char *buf, const char *fmt, va_list args) if (is_digit(*fmt)) field_width = skip_atoi(&fmt); else if (*fmt == '*') { + ++fmt; /* it's the next argument */ field_width = va_arg(args, int); if (field_width < 0) { @@ -184,6 +185,7 @@ int vsprintf(char *buf, const char *fmt, va_list args) if (is_digit(*fmt)) precision = skip_atoi(&fmt); else if (*fmt == '*') { + ++fmt; /* it's the next argument */ precision = va_arg(args, int); } diff --git a/mm/memory.c b/mm/memory.c index 1d9a185ba01c..c304ee84780f 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -734,8 +734,12 @@ static int try_to_share(unsigned long to_address, struct vm_area_struct * to_are if (!(from & PAGE_PRESENT)) return 0; /* if it is private, it must be clean to be shared */ - if ((from_area->vm_page_prot & PAGE_COW) && (from & PAGE_DIRTY)) - return 0; + if (from & PAGE_DIRTY) { + if (from_area->vm_page_prot & PAGE_COW) + return 0; + if (!(from_area->vm_page_prot & PAGE_RW)) + return 0; + } /* is the page reasonable at all? */ if (from >= high_memory) return 0; @@ -754,6 +758,8 @@ static int try_to_share(unsigned long to_address, struct vm_area_struct * to_are if (in_swap_cache(from)) { /* implies PAGE_DIRTY */ if (from_area->vm_page_prot & PAGE_COW) return 0; + if (!(from_area->vm_page_prot & PAGE_RW)) + return 0; } copy_page((from & PAGE_MASK), newpage); *(unsigned long *) to_page = newpage | to_area->vm_page_prot; @@ -763,6 +769,8 @@ static int try_to_share(unsigned long to_address, struct vm_area_struct * to_are if (in_swap_cache(from)) { if (from_area->vm_page_prot & PAGE_COW) return 0; + if (!(from_area->vm_page_prot & PAGE_RW)) + return 0; from |= PAGE_DIRTY; *(unsigned long *) from_page = from; delete_from_swap_cache(from); diff --git a/net/inet/icmp.c b/net/inet/icmp.c index 24fc614fb95e..5825002e8f1f 100644 --- a/net/inet/icmp.c +++ b/net/inet/icmp.c @@ -209,7 +209,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev) /* * Send it and free it once sent. */ - ip_queue_xmit(NULL, dev, skb, 1); + ip_queue_xmit(NULL, ndev, skb, 1); } diff --git a/net/inet/ncp.h b/net/inet/ncp.h deleted file mode 100644 index b12011c985b2..000000000000 --- a/net/inet/ncp.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * - * Kernel support for NCP - * - * Mark Evans 1994 - * - */ - -#ifndef _NCP_H -#define _NCP_H - -#include - -struct ncp_info -{ - unsigned short conn; /* connection number */ - unsigned char seq; /* sequence number */ - ipx_socket *ncp; /* ncp socket */ - ipx_socket *watchdog; /* watchdog socket */ - ipx_socket *mail; /* mail socket */ -}; - -#define NCP_TIMEOUT (3*HZ) -#define MAX_TIMEOUT 15 - -#endif /* _NCP_H */ diff --git a/net/inet/route.c b/net/inet/route.c index 4ea8dfb09c74..2fe7db265d7e 100644 --- a/net/inet/route.c +++ b/net/inet/route.c @@ -325,7 +325,7 @@ void ip_rt_add(short flags, unsigned long dst, unsigned long mask, * Update the loopback route */ - if (rt->rt_dev->flags & IFF_LOOPBACK) + if ((rt->rt_dev->flags & IFF_LOOPBACK) && !rt_loopback) rt_loopback = rt; /* -- 2.39.5