diff -u --recursive --new-file v2.1.122/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.1.122/linux/Documentation/Configure.help Thu Sep 17 17:53:34 1998 +++ linux/Documentation/Configure.help Sun Sep 20 23:22:45 1998 @@ -2457,8 +2457,9 @@ be inserted in and removed from the running kernel whenever you want). The module will be called unix.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. If you - try building this as a module and you are running kerneld, be sure - to add 'alias net-pf-1 unix' to your /etc/conf.module file. + try building this as a module and you have said Y to "Kernel module + loader support" above, be sure to add 'alias net-pf-1 unix' to your + /etc/conf.modules file. If unsure, say Y. @@ -7033,8 +7034,8 @@ Documentation/modules.txt. The module will be called serial.o. [WARNING: Do not compile this driver as a module if you are using non-standard serial ports, since the configuration information will - be lost when kerneld automatically unloads the driver. This - limitation may be lifted in the future.] + be lost if you unload the driver. This limitation may be lifted in + the future.] BTW1: If you have a mouseman serial mouse which is not recognized by the X window system, try running gpm first. diff -u --recursive --new-file v2.1.122/linux/Documentation/sound/AWE32 linux/Documentation/sound/AWE32 --- v2.1.122/linux/Documentation/sound/AWE32 Sun Jul 26 11:57:14 1998 +++ linux/Documentation/sound/AWE32 Fri Sep 18 22:33:55 1998 @@ -51,7 +51,7 @@ but the wavetable needs THREE! My working string is: "(CONFIGURE CTL044/1132685 (LD 2 (IO 0 (BASE 0x0620)) (IO 1 (BASE 0x0A20)) -(IO 3 (BASE 0x0E20)) (ACT Y) ))" +(IO 2 (BASE 0x0E20)) (ACT Y) ))" Resources 0x0620, 0x0A20 and 0x0E20 should work. Other on-board devices: Gameport and StereoEnhance are not required to be inited. diff -u --recursive --new-file v2.1.122/linux/MAINTAINERS linux/MAINTAINERS --- v2.1.122/linux/MAINTAINERS Thu Sep 17 17:53:34 1998 +++ linux/MAINTAINERS Tue Sep 22 23:31:18 1998 @@ -331,13 +331,7 @@ P: Paul Russell M: Paul.Russell@rustcorp.com.au W: http://www.adelaide.net.au/~rustcorp/ipfwchains/ipfwchains.html -S: Maintained - -IP FIREWALL -P: Paul Russell -M: Paul.Russell@rustcorp.com.au -W: http://www.adelaide.net.au/~rustcorp/ipfwchains/ipfwchains.html -S: Maintained +S: Supported IPX/SPX NETWORK LAYER P: Jay Schulist diff -u --recursive --new-file v2.1.122/linux/Makefile linux/Makefile --- v2.1.122/linux/Makefile Thu Sep 17 17:53:34 1998 +++ linux/Makefile Sun Sep 20 11:38:59 1998 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 122 +SUBLEVEL = 123 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) diff -u --recursive --new-file v2.1.122/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.1.122/linux/arch/i386/defconfig Wed Sep 9 14:51:05 1998 +++ linux/arch/i386/defconfig Sun Sep 20 23:52:40 1998 @@ -40,6 +40,7 @@ CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=y # CONFIG_PARPORT is not set +# CONFIG_APM is not set # # Plug and Play support @@ -238,7 +239,6 @@ # CONFIG_PC110_PAD is not set # CONFIG_UMISC is not set # CONFIG_QIC02_TAPE is not set -# CONFIG_APM is not set # CONFIG_WATCHDOG is not set # CONFIG_RTC is not set # CONFIG_VIDEO_DEV is not set @@ -277,6 +277,9 @@ # CONFIG_ROMFS_FS is not set CONFIG_AUTOFS_FS=y # CONFIG_UFS_FS is not set +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_SMD_DISKLABEL is not set +# CONFIG_SOLARIS_X86_PARTITION is not set CONFIG_DEVPTS_FS=y # CONFIG_MAC_PARTITION is not set # CONFIG_NLS is not set diff -u --recursive --new-file v2.1.122/linux/arch/i386/kernel/bios32.c linux/arch/i386/kernel/bios32.c --- v2.1.122/linux/arch/i386/kernel/bios32.c Wed Sep 9 14:51:05 1998 +++ linux/arch/i386/kernel/bios32.c Sat Sep 26 10:34:49 1998 @@ -1,7 +1,7 @@ /* * bios32.c - Low-Level PCI Access * - * $Id: bios32.c,v 1.45 1998/08/15 10:41:04 mj Exp $ + * $Id: bios32.c,v 1.48 1998/09/26 08:06:55 mj Exp $ * * Copyright 1993, 1994 Drew Eckhardt * Visionary Computing @@ -170,6 +170,7 @@ #define PCI_PROBE_CONF2 4 #define PCI_NO_SORT 0x100 #define PCI_BIOS_SORT 0x200 +#define PCI_NO_CHECKS 0x400 static unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2; @@ -343,14 +344,21 @@ * whether bus 00 contains a host bridge (this is similar to checking * techniques used in XFree86, but ours should be more reliable since we * attempt to make use of direct access hints provided by the PCI BIOS). + * + * This should be close to trivial, but it isn't, because there are buggy + * chipsets (yes, you guessed it, by Intel) that have no class ID. */ __initfunc(int pci_sanity_check(struct pci_access *a)) { - u16 dfn, class; + u16 dfn, x; + if (pci_probe & PCI_NO_CHECKS) + return 1; for(dfn=0; dfn < 0x100; dfn++) - if (!a->read_config_word(0, dfn, PCI_CLASS_DEVICE, &class) && - class == PCI_CLASS_BRIDGE_HOST) + if ((!a->read_config_word(0, dfn, PCI_CLASS_DEVICE, &x) && + x == PCI_CLASS_BRIDGE_HOST) || + (!a->read_config_word(0, dfn, PCI_VENDOR_ID, &x) && + x == PCI_VENDOR_ID_INTEL)) return 1; DBG("PCI: Sanity check failed\n"); return 0; @@ -945,7 +953,7 @@ __initfunc(void pcibios_fixup_peer_bridges(void)) { struct pci_bus *b = &pci_root; - int i, cnt=-1; + int i, n, cnt=-1; struct pci_dev *d; #ifdef CONFIG_PCI_DIRECT @@ -960,8 +968,8 @@ for(d=b->devices; d; d=d->sibling) if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST) cnt++; - do { - int n = b->subordinate+1; + n = b->subordinate + 1; + while (n <= 0xff) { int found = 0; u16 l; for(i=0; i<256; i += 8) @@ -973,8 +981,9 @@ l == PCI_CLASS_BRIDGE_HOST) cnt++; } - if (found && cnt > 0) { - cnt--; + if (cnt-- <= 0) + break; + if (found) { printk("PCI: Discovered primary peer bus %02x\n", n); b = kmalloc(sizeof(*b), GFP_KERNEL); memset(b, 0, sizeof(*b)); @@ -983,9 +992,10 @@ b->number = b->secondary = n; b->subordinate = 0xff; b->subordinate = pci_scan_bus(b); - break; + n = b->subordinate; } - } while (i < 256); + n++; + } } /* @@ -1146,11 +1156,11 @@ #endif #ifdef CONFIG_PCI_DIRECT else if (!strcmp(str, "conf1")) { - pci_probe = PCI_PROBE_CONF1; + pci_probe = PCI_PROBE_CONF1 | PCI_NO_CHECKS; return NULL; } else if (!strcmp(str, "conf2")) { - pci_probe = PCI_PROBE_CONF2; + pci_probe = PCI_PROBE_CONF2 | PCI_NO_CHECKS; return NULL; } #endif diff -u --recursive --new-file v2.1.122/linux/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c --- v2.1.122/linux/arch/i386/kernel/io_apic.c Thu Sep 17 17:53:34 1998 +++ linux/arch/i386/kernel/io_apic.c Fri Sep 25 16:58:13 1998 @@ -371,9 +371,16 @@ { switch (mp_bus_id_to_type[bus]) { - case MP_BUS_ISA: /* ISA pin, edge */ - { - trigger = 0; + case MP_BUS_ISA: { + /* ISA pin, read the Edge/Level control register */ + unsigned int irq = mp_irqs[idx].mpc_dstirq; + if (irq < 16) { + unsigned int port = 0x4d0 + (irq >> 3); + trigger = (inb(port) >> (irq & 7)) & 1; + break; + } + printk("Broken MPtable reports ISA irq %d\n", irq); + trigger = 1; break; } case MP_BUS_PCI: /* PCI pin, level */ @@ -1009,8 +1016,10 @@ /* * If there is no IRQ handler or it was disabled, exit early. */ - if (!action) + if (!action) { +printk("Unhandled edge irq %d (%x %p)\n", irq, status, desc->action); return; + } /* * Edge triggered interrupts need to remember @@ -1061,8 +1070,10 @@ spin_unlock(&irq_controller_lock); /* Exit early if we had no action or it was disabled */ - if (!action) + if (!action) { +printk("Unhandled level irq %d (%x)\n", irq, status); return; + } handle_IRQ_event(irq, regs, action); diff -u --recursive --new-file v2.1.122/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c --- v2.1.122/linux/arch/i386/kernel/irq.c Thu Sep 17 17:53:34 1998 +++ linux/arch/i386/kernel/irq.c Fri Sep 25 16:42:13 1998 @@ -664,8 +664,10 @@ spin_unlock(&irq_controller_lock); /* Exit early if we had no action or it was disabled */ - if (!action) + if (!action) { +printk("Unhandled irq %d (%x)\n", irq, desc->status); return; + } handle_IRQ_event(irq, regs, action); diff -u --recursive --new-file v2.1.122/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c --- v2.1.122/linux/arch/i386/kernel/process.c Thu Sep 17 17:53:34 1998 +++ linux/arch/i386/kernel/process.c Thu Sep 17 17:41:51 1998 @@ -540,10 +540,10 @@ static inline void unlazy_fpu(struct task_struct *tsk) { if (tsk->flags & PF_USEDFPU) { - tsk->flags &= ~PF_USEDFPU; __asm__("fnsave %0":"=m" (tsk->tss.i387)); - stts(); asm volatile("fwait"); + tsk->flags &= ~PF_USEDFPU; + stts(); } } @@ -737,8 +737,11 @@ asm volatile("lldt %0": :"g" (*(unsigned short *)&next->tss.ldt)); /* Re-load page tables */ - if (next->tss.cr3 != prev->tss.cr3) - asm volatile("movl %0,%%cr3": :"r" (next->tss.cr3)); + { + unsigned long new_cr3 = next->tss.cr3; + if (new_cr3 != prev->tss.cr3) + asm volatile("movl %0,%%cr3": :"r" (new_cr3)); + } /* * Restore %fs and %gs. diff -u --recursive --new-file v2.1.122/linux/drivers/block/genhd.c linux/drivers/block/genhd.c --- v2.1.122/linux/drivers/block/genhd.c Thu Sep 17 17:53:35 1998 +++ linux/drivers/block/genhd.c Tue Sep 22 16:41:05 1998 @@ -426,8 +426,7 @@ && (q->sector & 63) == 1 && (q->end_sector & 63) == 63) { unsigned int heads = q->end_head + 1; - if (heads == 15 || heads == 16 || - heads == 32 || heads == 64 || + if (heads == 32 || heads == 64 || heads == 128 || heads == 240 || heads == 255) { (void) ide_xlate_1024(dev, heads, " [PTBL]"); diff -u --recursive --new-file v2.1.122/linux/drivers/char/console.c linux/drivers/char/console.c --- v2.1.122/linux/drivers/char/console.c Thu Aug 6 14:06:31 1998 +++ linux/drivers/char/console.c Thu Sep 17 09:42:28 1998 @@ -47,7 +47,6 @@ * - video_num_columns * - video_num_lines * - video_size_row - * - video_screen_size * - can_do_color * * The abstract console driver provides a generic interface for a text @@ -108,8 +107,6 @@ struct consw *conswitchp = NULL; -static int vesa_blank_mode = 0; /* 0:none 1:suspendV 2:suspendH 3:powerdown */ - /* A bitmap for codes <32. A bit of 1 indicates that the code * corresponding to that bit number invokes some special action * (such as cursor movement) and should not be displayed as a @@ -133,21 +130,26 @@ static struct termios *console_termios_locked[MAX_NR_CONSOLES]; struct vc vc_cons [MAX_NR_CONSOLES]; +static struct consw *con_driver_map[MAX_NR_CONSOLES]; + static int con_open(struct tty_struct *, struct file *); static void vc_init(unsigned int console, unsigned int rows, unsigned int cols, int do_clear); static void blank_screen(void); -static void unblank_screen(void); static void gotoxy(int currcons, int new_x, int new_y); static void save_cur(int currcons); static void reset_terminal(int currcons, int do_clear); static void con_flush_chars(struct tty_struct *tty); +static void set_vesa_blanking(unsigned long arg); +static void set_cursor(int currcons); +static void hide_cursor(int currcons); static int printable = 0; /* Is console ready for printing? */ int do_poke_blanked_console = 0; int console_blanked = 0; +static int vesa_blank_mode = 0; /* 0:none 1:suspendV 2:suspendH 3:powerdown */ static int blankinterval = 10*60*HZ; static int vesa_off_interval = 0; @@ -179,17 +181,16 @@ DECLARE_TASK_QUEUE(con_task_queue); /* + * For the same reason, we defer scrollback to the console_bh. + */ +static int scrollback_delta = 0; + +/* * Low-Level Functions */ #define IS_FG (currcons == fg_console) -#define IS_VISIBLE (*display_fg == vc_cons[currcons].d) - -#ifdef VT_BUF_VRAM_ONLY -#define DO_UPDATE 0 -#else -#define DO_UPDATE IS_VISIBLE -#endif +#define IS_VISIBLE CON_IS_VISIBLE(vc_cons[currcons].d) static inline unsigned short *screenpos(int currcons, int offset, int viewed) { @@ -197,13 +198,10 @@ return p; } -static void scrolldelta(int lines) +static inline void scrolldelta(int lines) { - int currcons = fg_console; - - clear_selection(); - if (vcmode == KD_TEXT) - sw->con_scrolldelta(vc_cons[currcons].d, lines); + scrollback_delta += lines; + mark_bh(CONSOLE_BH); } static void scrup(int currcons, unsigned int t, unsigned int b, int nr) @@ -242,7 +240,6 @@ static void do_update_region(int currcons, unsigned long start, int count) { -#ifndef VT_BUF_VRAM_ONLY unsigned int xx, yy, offset; u16 *p; @@ -279,13 +276,15 @@ xx = 0; yy++; } -#endif } void update_region(int currcons, unsigned long start, int count) { - if (DO_UPDATE) + if (IS_VISIBLE) { + hide_cursor(currcons); do_update_region(currcons, start, count); + set_cursor(currcons); + } } /* Structure of attributes is hardware-dependent */ @@ -295,7 +294,6 @@ if (sw->con_build_attr) return sw->con_build_attr(vc_cons[currcons].d, _color, _intensity, _blink, _underline, _reverse); -#ifndef VT_BUF_VRAM_ONLY /* * ++roman: I completely changed the attribute format for monochrome * mode (!can_do_color). The formerly used MDA (monochrome display @@ -327,9 +325,6 @@ a <<= 1; return a; } -#else - return 0; -#endif } static void update_attr(int currcons) @@ -348,7 +343,6 @@ p = screenpos(currcons, offset, viewed); if (sw->con_invert_region) sw->con_invert_region(vc_cons[currcons].d, p, count); -#ifndef VT_BUF_VRAM_ONLY else { u16 *q = p; int cnt = count; @@ -369,8 +363,8 @@ } } } -#endif - update_region(currcons, (unsigned long) p, count); + if (IS_VISIBLE) + do_update_region(currcons, (unsigned long) p, count); } /* used by selection: complement pointer position */ @@ -382,7 +376,7 @@ if (p) { scr_writew(old, p); - if (DO_UPDATE) + if (IS_VISIBLE) sw->con_putc(vc_cons[currcons].d, old, oldy, oldx); } if (offset == -1) @@ -393,7 +387,7 @@ old = scr_readw(p); new = old ^ complement_mask; scr_writew(new, p); - if (DO_UPDATE) { + if (IS_VISIBLE) { oldx = (offset >> 1) % video_num_columns; oldy = (offset >> 1) / video_num_columns; sw->con_putc(vc_cons[currcons].d, new, oldy, oldx); @@ -410,7 +404,7 @@ scr_writew(scr_readw(p), p + nr); scr_memsetw(q, video_erase_char, nr*2); need_wrap = 0; - if (DO_UPDATE) { + if (IS_VISIBLE) { unsigned short oldattr = attr; sw->con_bmove(vc_cons[currcons].d,y,x,y,x+nr,1, video_num_columns-x-nr); @@ -433,7 +427,7 @@ } scr_memsetw(p, video_erase_char, nr*2); need_wrap = 0; - if (DO_UPDATE) { + if (IS_VISIBLE) { unsigned short oldattr = attr; sw->con_bmove(vc_cons[currcons].d, y, x+nr, y, x, 1, video_num_columns-x-nr); @@ -461,7 +455,7 @@ if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000; if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700; scr_writew(i, (u16 *) pos); - if (DO_UPDATE) + if (IS_VISIBLE) sw->con_putc(vc_cons[currcons].d, i, y, x); } @@ -471,14 +465,14 @@ clear_selection(); if (softcursor_original != -1) { scr_writew(softcursor_original,(u16 *) pos); - if (DO_UPDATE) + if (IS_VISIBLE) sw->con_putc(vc_cons[currcons].d, softcursor_original, y, x); softcursor_original = -1; } sw->con_cursor(vc_cons[currcons].d,CM_ERASE); } -void set_cursor(int currcons) +static void set_cursor(int currcons) { if (!IS_FG || console_blanked || vcmode == KD_GRAPHICS) return; @@ -503,9 +497,8 @@ pos = origin + video_size_row*y + 2*x; } -static inline void save_screen(void) +static inline void save_screen(int currcons) { - int currcons = fg_console; if (sw->con_save_screen) sw->con_save_screen(vc_cons[currcons].d); } @@ -514,45 +507,55 @@ * Redrawing of screen */ -void update_screen(int new_console) +void redraw_screen(int new_console, int is_switch) { - int currcons = fg_console; int redraw = 1; - int old_console; + int currcons, old_console; static int lock = 0; - struct vc_data **display; if (lock) return; if (!vc_cons_allocated(new_console)) { /* strange ... */ - printk("update_screen: tty %d not allocated ??\n", new_console+1); + printk("redraw_screen: tty %d not allocated ??\n", new_console+1); return; } lock = 1; - hide_cursor(currcons); - if (fg_console != new_console) { - display = vc_cons[new_console].d->vc_display_fg; - old_console = (*display) ? (*display)->vc_num : fg_console; - *display = vc_cons[new_console].d; - fg_console = new_console; - currcons = old_console; - if (!IS_VISIBLE) - set_origin(currcons); + if (is_switch) { + currcons = fg_console; + hide_cursor(currcons); + if (fg_console != new_console) { + struct vc_data **display = vc_cons[new_console].d->vc_display_fg; + old_console = (*display) ? (*display)->vc_num : fg_console; + *display = vc_cons[new_console].d; + fg_console = new_console; + currcons = old_console; + if (!IS_VISIBLE) { + save_screen(currcons); + set_origin(currcons); + } + currcons = new_console; + if (old_console == new_console) + redraw = 0; + } + } else { currcons = new_console; - if (old_console == new_console) - redraw = 0; + hide_cursor(currcons); } + if (redraw) { set_origin(currcons); - if (sw->con_switch(vc_cons[currcons].d)) + set_palette(currcons); + if (sw->con_switch(vc_cons[currcons].d) && vcmode != KD_GRAPHICS) /* Update the screen contents */ do_update_region(currcons, origin, screenbuf_size/2); } set_cursor(currcons); - set_leds(); - compute_shiftstate(); + if (is_switch) { + set_leds(); + compute_shiftstate(); + } lock = 0; } @@ -565,27 +568,31 @@ return (i < MAX_NR_CONSOLES && vc_cons[i].d); } -void visual_init(int currcons) +static void visual_init(int currcons, int init) { /* ++Geert: sw->con_init determines console size */ sw = conswitchp; + if (con_driver_map[currcons]) + sw = con_driver_map[currcons]; cons_num = currcons; display_fg = &master_display_fg; vc_cons[currcons].d->vc_uni_pagedir_loc = &vc_cons[currcons].d->vc_uni_pagedir; vc_cons[currcons].d->vc_uni_pagedir = 0; hi_font_mask = 0; complement_mask = 0; - sw->con_init(vc_cons[currcons].d, 1); + can_do_color = 0; + sw->con_init(vc_cons[currcons].d, init); if (!complement_mask) complement_mask = can_do_color ? 0x7700 : 0x0800; + s_complement_mask = complement_mask; video_size_row = video_num_columns<<1; - video_screen_size = video_num_lines*video_size_row; + screenbuf_size = video_num_lines*video_size_row; } -int vc_allocate(unsigned int currcons, int init) /* return 0 on success */ +int vc_allocate(unsigned int currcons) /* return 0 on success */ { if (currcons >= MAX_NR_CONSOLES) - return -ENXIO; + return -ENXIO; if (!vc_cons[currcons].d) { long p, q; @@ -595,7 +602,7 @@ /* due to the granularity of kmalloc, we waste some memory here */ /* the alloc is done in two steps, to optimize the common situation - of a 25x80 console (structsize=216, video_screen_size=4000) */ + of a 25x80 console (structsize=216, screenbuf_size=4000) */ /* although the numbers above are not valid since long ago, the point is still up-to-date and the comment still has its value even if only as a historical artifact. --mj, July 1998 */ @@ -604,22 +611,19 @@ return -ENOMEM; vc_cons[currcons].d = (struct vc_data *)p; vt_cons[currcons] = (struct vt_struct *)(p+sizeof(struct vc_data)); - visual_init(currcons); - q = (long)kmalloc(video_screen_size, GFP_KERNEL); + visual_init(currcons, 1); + if (!*vc_cons[currcons].d->vc_uni_pagedir_loc) + con_set_default_unimap(currcons); + q = (long)kmalloc(screenbuf_size, GFP_KERNEL); if (!q) { kfree_s((char *) p, structsize); vc_cons[currcons].d = NULL; vt_cons[currcons] = NULL; return -ENOMEM; } - con_set_default_unimap(currcons); screenbuf = (unsigned short *) q; kmalloced = 1; - screenbuf_size = video_screen_size; - if (!sw->con_save_screen) - init = 0; /* If console does not have save_screen routine, - we should clear the screen */ - vc_init(currcons, video_num_lines, video_num_columns, !init); + vc_init(currcons, video_num_lines, video_num_columns, 1); } return 0; } @@ -669,12 +673,12 @@ oll = video_num_lines; occ = video_num_columns; osr = video_size_row; - oss = video_screen_size; + oss = screenbuf_size; video_num_lines = ll; video_num_columns = cc; video_size_row = sr; - video_screen_size = ss; + screenbuf_size = ss; rlth = MIN(osr, sr); rrem = sr - rlth; @@ -719,11 +723,10 @@ *cws = ws; } - if (IS_FG && vt_cons[fg_console]->vc_mode == KD_TEXT) - update_screen(fg_console); + if (IS_VISIBLE) + update_screen(currcons); } - set_cursor(fg_console); return 0; } @@ -884,7 +887,7 @@ case 0: /* erase from cursor to end of display */ count = (scr_end-pos)>>1; start = (unsigned short *) pos; - if (DO_UPDATE) { + if (IS_VISIBLE) { /* do in two stages */ sw->con_clear(vc_cons[currcons].d, y, x, 1, video_num_columns-x); @@ -896,7 +899,7 @@ case 1: /* erase from start to cursor */ count = ((pos-origin)>>1)+1; start = (unsigned short *) origin; - if (DO_UPDATE) { + if (IS_VISIBLE) { /* do in two stages */ sw->con_clear(vc_cons[currcons].d, 0, 0, y, video_num_columns); @@ -907,7 +910,7 @@ case 2: /* erase whole display */ count = video_num_columns * video_num_lines; start = (unsigned short *) origin; - if (DO_UPDATE) + if (IS_VISIBLE) sw->con_clear(vc_cons[currcons].d, 0, 0, video_num_lines, video_num_columns); @@ -928,21 +931,21 @@ case 0: /* erase from cursor to end of line */ count = video_num_columns-x; start = (unsigned short *) pos; - if (DO_UPDATE) + if (IS_VISIBLE) sw->con_clear(vc_cons[currcons].d, y, x, 1, video_num_columns-x); break; case 1: /* erase from start of line to cursor */ start = (unsigned short *) (pos - (x<<1)); count = x+1; - if (DO_UPDATE) + if (IS_VISIBLE) sw->con_clear(vc_cons[currcons].d, y, 0, 1, x + 1); break; case 2: /* erase whole line */ start = (unsigned short *) (pos - (x<<1)); count = video_num_columns; - if (DO_UPDATE) + if (IS_VISIBLE) sw->con_clear(vc_cons[currcons].d, y, 0, 1, video_num_columns); break; @@ -962,7 +965,7 @@ count = (vpar > video_num_columns-x) ? (video_num_columns-x) : vpar; scr_memsetw((unsigned short *) pos, video_erase_char, 2 * count); - if (DO_UPDATE) + if (IS_VISIBLE) sw->con_clear(vc_cons[currcons].d, y, x, 1, count); need_wrap = 0; } @@ -1138,7 +1141,7 @@ case 5: /* Inverted screen on/off */ if (decscnm != on_off) { decscnm = on_off; - invert_screen(currcons, 0, video_screen_size, 0); + invert_screen(currcons, 0, screenbuf_size, 0); update_attr(currcons); } break; @@ -1350,6 +1353,7 @@ set_leds(); cursor_type = CUR_DEFAULT; + complement_mask = s_complement_mask; default_attr(currcons); update_attr(currcons); @@ -1487,7 +1491,7 @@ vc_state = ESpalette; return; } else if (c=='R') { /* reset palette */ - reset_palette (currcons); + reset_palette(currcons); vc_state = ESnormal; } else vc_state = ESnormal; @@ -1503,7 +1507,7 @@ palette[i++] += par[j++]; palette[i] = 16*par[j++]; palette[i] += par[j]; - set_palette() ; + set_palette(currcons); vc_state = ESnormal; } } else @@ -1548,6 +1552,16 @@ return; } break; + case 'm': + if (ques) { + clear_selection(); + if (par[0]) + complement_mask = par[0]<<8 | par[1]; + else + complement_mask = s_complement_mask; + return; + } + break; case 'n': if (!ques) { if (par[0] == 5) @@ -1729,14 +1743,10 @@ static int do_con_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count) { -#ifdef VT_BUF_VRAM_ONLY -#define FLUSH do { } while(0); -#else #define FLUSH if (draw_x >= 0) { \ sw->con_putcs(vc_cons[currcons].d, (u16 *)draw_from, (u16 *)draw_to-(u16 *)draw_from, y, draw_x); \ draw_x = -1; \ } -#endif int c, tc, ok, n = 0, draw_x = -1; unsigned int currcons; @@ -1864,7 +1874,7 @@ ((attr & ~himask) << 8) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) : (attr << 8) + tc, (u16 *) pos); - if (DO_UPDATE && draw_x < 0) { + if (IS_VISIBLE && draw_x < 0) { draw_x = x; draw_from = pos; } @@ -1901,7 +1911,6 @@ if (want_console >= 0) { if (want_console != fg_console && vc_cons_allocated(want_console)) { hide_cursor(fg_console); - save_screen(); change_console(want_console); /* we only changed when the console had already been allocated - a new console is not created @@ -1913,6 +1922,13 @@ do_poke_blanked_console = 0; poke_blanked_console(); } + if (scrollback_delta) { + int currcons = fg_console; + clear_selection(); + if (vcmode == KD_TEXT) + sw->con_scrolldelta(vc_cons[currcons].d, scrollback_delta); + scrollback_delta = 0; + } } /* @@ -2015,7 +2031,7 @@ NULL, vt_console_device, keyboard_wait_for_keypress, - do_unblank_screen, + unblank_screen, NULL, CON_PRINTBUFFER, -1, @@ -2045,7 +2061,7 @@ case 3: return paste_selection(tty); case 4: - do_unblank_screen(); + unblank_screen(); return 0; case 5: return sel_loadlut(arg); @@ -2173,7 +2189,7 @@ currcons = MINOR(tty->device) - tty->driver.minor_start; - i = vc_allocate(currcons, 0); + i = vc_allocate(currcons); if (i) return i; @@ -2194,7 +2210,7 @@ video_num_columns = cols; video_num_lines = rows; video_size_row = cols<<1; - video_screen_size = video_num_lines * video_size_row; + screenbuf_size = video_num_lines * video_size_row; set_origin(currcons); pos = origin; @@ -2279,11 +2295,10 @@ kmem_start += sizeof(struct vc_data); vt_cons[currcons] = (struct vt_struct *) kmem_start; kmem_start += sizeof(struct vt_struct); - visual_init(currcons); + visual_init(currcons, 1); screenbuf = (unsigned short *) kmem_start; - kmem_start += video_screen_size; + kmem_start += screenbuf_size; kmalloced = 0; - screenbuf_size = video_screen_size; vc_init(currcons, video_num_lines, video_num_columns, currcons || !sw->con_save_screen); for (j=k=0; j<16; j++) { @@ -2295,11 +2310,10 @@ currcons = fg_console = 0; master_display_fg = vc_cons[currcons].d; set_origin(currcons); - save_screen(); + save_screen(currcons); gotoxy(currcons,x,y); csi_J(currcons, 0); update_screen(fg_console); - set_cursor(currcons); printk("Console: %s %s %dx%d", can_do_color ? "colour" : "mono", display_desc, video_num_columns, video_num_lines); @@ -2315,47 +2329,85 @@ return kmem_start; } +static void clear_buffer_attributes(int currcons) +{ + unsigned short *p = (unsigned short *) origin; + int count = screenbuf_size/2; + int mask = hi_font_mask | 0xff; + + for (; count > 0; count--, p++) { + scr_writew((scr_readw(p)&mask) | (video_erase_char&~mask), p); + } +} + /* * If we support more console drivers, this function is used * when a driver wants to take over some existing consoles * and become default driver for newly opened ones. */ -#ifndef VT_BUF_VRAM_ONLY - void take_over_console(struct consw *csw, int first, int last, int deflt) { - int i; + int i, j = -1; const char *desc; - if (deflt) - conswitchp = csw; desc = csw->con_startup(); if (!desc) return; + if (deflt) + conswitchp = csw; for (i = first; i <= last; i++) { + int old_was_color; + int currcons = i; + + con_driver_map[i] = csw; + if (!vc_cons[i].d || !vc_cons[i].d->vc_sw) continue; - if (i == fg_console && - vc_cons[i].d->vc_sw->con_save_screen) - vc_cons[i].d->vc_sw->con_save_screen(vc_cons[i].d); + + j = i; + if (IS_VISIBLE) + save_screen(i); + old_was_color = vc_cons[i].d->vc_can_do_color; vc_cons[i].d->vc_sw->con_deinit(vc_cons[i].d); - vc_cons[i].d->vc_sw = csw; - vc_cons[i].d->vc_sw->con_init(vc_cons[i].d, 0); - } - printk("Console: switching to %s %s %dx%d\n", - vc_cons[fg_console].d->vc_can_do_color ? "colour" : "mono", - desc, vc_cons[fg_console].d->vc_cols, vc_cons[fg_console].d->vc_rows); - set_palette(); + visual_init(i, 0); + update_attr(i); + + /* If the console changed between mono <-> color, then + * the attributes in the screenbuf will be wrong. The + * following resets all attributes to something sane. + */ + if (old_was_color != vc_cons[i].d->vc_can_do_color) + clear_buffer_attributes(i); + + if (IS_VISIBLE) + update_screen(i); + } + printk("Console: switching "); + if (!deflt) + printk("consoles %d-%d ", first, last); + if (j >= 0) + printk("to %s %s %dx%d\n", + vc_cons[j].d->vc_can_do_color ? "colour" : "mono", + desc, vc_cons[j].d->vc_cols, vc_cons[j].d->vc_rows); + else + printk("to %s\n", desc); } -#endif +void give_up_console(struct consw *csw) +{ + int i; + + for(i = 0; i < MAX_NR_CONSOLES; i++) + if (con_driver_map[i] == csw) + con_driver_map[i] = NULL; +} /* * Screen blanking */ -void set_vesa_blanking(unsigned long arg) +static void set_vesa_blanking(unsigned long arg) { char *argp = (char *)arg + 1; unsigned int mode; @@ -2363,13 +2415,7 @@ vesa_blank_mode = (mode < 4) ? mode : 0; } -void vesa_blank(void) -{ - struct vc_data *c = vc_cons[fg_console].d; - c->vc_sw->con_blank(c, vesa_blank_mode + 1); -} - -void vesa_powerdown(void) +static void vesa_powerdown(void) { struct vc_data *c = vc_cons[fg_console].d; /* @@ -2389,7 +2435,7 @@ } } -void vesa_powerdown_screen(void) +static void vesa_powerdown_screen(void) { timer_active &= ~(1<con_blank(vc_cons[currcons].d, -1); console_blanked = fg_console + 1; set_origin(currcons); @@ -2416,13 +2462,13 @@ } /* don't blank graphics */ - if (vt_cons[fg_console]->vc_mode != KD_TEXT) { + if (vcmode != KD_TEXT) { console_blanked = fg_console + 1; return; } - hide_cursor(fg_console); - if(vesa_off_interval && !nopowersave) { + hide_cursor(currcons); + if (vesa_off_interval) { timer_table[BLANK_TIMER].fn = vesa_powerdown_screen; timer_table[BLANK_TIMER].expires = jiffies + vesa_off_interval; timer_active |= (1<con_blank(vc_cons[currcons].d, 1); console_blanked = fg_console + 1; if (i) set_origin(currcons); - if(!nopowersave) - { #ifdef CONFIG_APM - if (apm_display_blank()) - return; + if (apm_display_blank()) + return; #endif - vesa_blank(); - } + if (vesa_blank_mode) + sw->con_blank(vc_cons[currcons].d, vesa_blank_mode + 1); } -void do_unblank_screen(void) +void unblank_screen(void) { int currcons; + if (!console_blanked) return; if (!vc_cons_allocated(fg_console)) { @@ -2480,11 +2525,6 @@ do_blank_screen(0); } -static void unblank_screen(void) -{ - do_unblank_screen(); -} - void poke_blanked_console(void) { timer_active &= ~(1<vc_mode != KD_GRAPHICS) - vc_cons[fg_console].d->vc_sw->con_set_palette(vc_cons[fg_console].d, color_table); + if (vcmode != KD_GRAPHICS) + sw->con_set_palette(vc_cons[currcons].d, color_table); } -int set_get_cmap(unsigned char *arg, int set) +static int set_get_cmap(unsigned char *arg, int set) { int i, j, k; @@ -2526,13 +2566,14 @@ } if (set) { for (i = 0; i < MAX_NR_CONSOLES; i++) - if (vc_cons_allocated(i)) + if (vc_cons_allocated(i)) { for (j = k = 0; j < 16; j++) { vc_cons[i].d->vc_palette[k++] = default_red[j]; vc_cons[i].d->vc_palette[k++] = default_grn[j]; vc_cons[i].d->vc_palette[k++] = default_blu[j]; } - set_palette(); + set_palette(i); + } } return 0; } @@ -2542,25 +2583,25 @@ * map, 3 bytes per colour, 16 colours, range from 0 to 255. */ -int con_set_cmap (unsigned char *arg) +int con_set_cmap(unsigned char *arg) { return set_get_cmap (arg,1); } -int con_get_cmap (unsigned char *arg) +int con_get_cmap(unsigned char *arg) { return set_get_cmap (arg,0); } -void reset_palette (int currcons) +void reset_palette(int currcons) { - int j, k ; + int j, k; for (j=k=0; j<16; j++) { palette[k++] = default_red[j]; palette[k++] = default_grn[j]; palette[k++] = default_blu[j]; } - set_palette() ; + set_palette(currcons); } /* @@ -2635,7 +2676,9 @@ } op->data = temp; } + disable_bh(CONSOLE_BH); rc = sw->con_font_op(vc_cons[currcons].d, op); + enable_bh(CONSOLE_BH); op->data = old_op.data; if (!rc && !set) { int c = (op->width+7)/8 * 32 * op->charcount; @@ -2721,7 +2764,7 @@ EXPORT_SYMBOL(default_blu); EXPORT_SYMBOL(video_font_height); EXPORT_SYMBOL(video_scan_lines); +EXPORT_SYMBOL(vc_resize); -#ifndef VT_BUF_VRAM_ONLY EXPORT_SYMBOL(take_over_console); -#endif +EXPORT_SYMBOL(give_up_console); diff -u --recursive --new-file v2.1.122/linux/drivers/char/console_macros.h linux/drivers/char/console_macros.h --- v2.1.122/linux/drivers/char/console_macros.h Sun Jul 26 11:57:15 1998 +++ linux/drivers/char/console_macros.h Thu Sep 17 09:35:03 1998 @@ -26,8 +26,6 @@ #define utf (vc_cons[currcons].d->vc_utf) #define utf_count (vc_cons[currcons].d->vc_utf_count) #define utf_char (vc_cons[currcons].d->vc_utf_char) -#define video_mem_start (vc_cons[currcons].d->vc_video_mem_start) -#define video_mem_end (vc_cons[currcons].d->vc_video_mem_end) #define video_erase_char (vc_cons[currcons].d->vc_video_erase_char) #define disp_ctrl (vc_cons[currcons].d->vc_disp_ctrl) #define toggle_meta (vc_cons[currcons].d->vc_toggle_meta) @@ -64,6 +62,7 @@ #define cursor_type (vc_cons[currcons].d->vc_cursor_type) #define display_fg (vc_cons[currcons].d->vc_display_fg) #define complement_mask (vc_cons[currcons].d->vc_complement_mask) +#define s_complement_mask (vc_cons[currcons].d->vc_s_complement_mask) #define hi_font_mask (vc_cons[currcons].d->vc_hi_font_mask) #define vcmode (vt_cons[currcons]->vc_mode) diff -u --recursive --new-file v2.1.122/linux/drivers/char/consolemap.c linux/drivers/char/consolemap.c --- v2.1.122/linux/drivers/char/consolemap.c Tue Jul 28 14:21:08 1998 +++ linux/drivers/char/consolemap.c Thu Sep 17 09:35:03 1998 @@ -576,6 +576,24 @@ } int +con_copy_unimap(int dstcon, int srccon) +{ + struct vc_data *sconp = vc_cons[srccon].d; + struct vc_data *dconp = vc_cons[dstcon].d; + struct uni_pagedir *q; + + if (!vc_cons_allocated(srccon) || !*sconp->vc_uni_pagedir_loc) + return -EINVAL; + if (*dconp->vc_uni_pagedir_loc == *sconp->vc_uni_pagedir_loc) + return 0; + con_free_unimap(dstcon); + q = (struct uni_pagedir *)*sconp->vc_uni_pagedir_loc; + q->refcount++; + *dconp->vc_uni_pagedir_loc = (long)q; + return 0; +} + +int con_get_unimap(int con, ushort ct, ushort *uct, struct unipair *list) { int i, j, k, ect; diff -u --recursive --new-file v2.1.122/linux/drivers/char/esp.c linux/drivers/char/esp.c --- v2.1.122/linux/drivers/char/esp.c Tue Jul 28 14:21:08 1998 +++ linux/drivers/char/esp.c Fri Sep 25 17:14:58 1998 @@ -102,7 +102,7 @@ #define WAKEUP_CHARS 1024 static char *serial_name = "ESP serial driver"; -static char *serial_version = "2.1"; +static char *serial_version = "2.2"; static DECLARE_TASK_QUEUE(tq_esp); @@ -2615,6 +2615,9 @@ } memset((void *)info, 0, sizeof(struct esp_struct)); + /* rx_trigger, tx_trigger are needed by autoconfig */ + info->config.rx_trigger = rx_trigger; + info->config.tx_trigger = tx_trigger; i = 0; offset = 0; @@ -2644,8 +2647,6 @@ info->callout_termios = esp_callout_driver.init_termios; info->normal_termios = esp_driver.init_termios; info->config.rx_timeout = rx_timeout; - info->config.rx_trigger = rx_trigger; - info->config.tx_trigger = tx_trigger; info->config.flow_on = flow_on; info->config.flow_off = flow_off; info->config.pio_threshold = pio_threshold; @@ -2681,6 +2682,9 @@ } memset((void *)info, 0, sizeof(struct esp_struct)); + /* rx_trigger, tx_trigger are needed by autoconfig */ + info->config.rx_trigger = rx_trigger; + info->config.tx_trigger = tx_trigger; if (offset == 56) { i++; diff -u --recursive --new-file v2.1.122/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c --- v2.1.122/linux/drivers/char/pc_keyb.c Wed Sep 9 14:51:07 1998 +++ linux/drivers/char/pc_keyb.c Fri Sep 25 17:21:04 1998 @@ -611,13 +611,18 @@ void __init pckbd_init_hw(void) { + disable_irq(KEYBOARD_IRQ); + /* Flush any pending input. */ kbd_clear_input(); if (kbd_startup_reset) { char *msg = initialize_kbd(); - if (msg) + if (msg) { printk(KERN_WARNING "initialize_kbd: %s\n", msg); + aux_device_present = 0; + return; + } } request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL); diff -u --recursive --new-file v2.1.122/linux/drivers/char/selection.c linux/drivers/char/selection.c --- v2.1.122/linux/drivers/char/selection.c Tue Jul 28 14:21:08 1998 +++ linux/drivers/char/selection.c Thu Sep 17 09:35:03 1998 @@ -123,7 +123,7 @@ int i, ps, pe; unsigned int currcons = fg_console; - do_unblank_screen(); + unblank_screen(); poke_blanked_console(); { unsigned short *args, xs, ys, xe, ye; diff -u --recursive --new-file v2.1.122/linux/drivers/char/sysrq.c linux/drivers/char/sysrq.c --- v2.1.122/linux/drivers/char/sysrq.c Tue Jul 28 14:21:08 1998 +++ linux/drivers/char/sysrq.c Thu Sep 17 09:35:03 1998 @@ -1,6 +1,6 @@ /* -*- linux-c -*- * - * $Id: sysrq.c,v 1.7 1997/11/06 15:57:09 mj Exp $ + * $Id: sysrq.c,v 1.15 1998/08/23 14:56:41 mj Exp $ * * Linux Magic System Request Key Hacks * @@ -70,12 +70,14 @@ printk("Keyboard mode set to XLATE\n"); } break; +#ifdef CONFIG_VT case 'k': /* K -- SAK */ printk("SAK\n"); if (tty) do_SAK(tty); reset_vc(fg_console); break; +#endif case 'b': /* B -- boot immediately */ printk("Resetting\n"); machine_restart(NULL); @@ -131,8 +133,10 @@ default: /* Unknown: help */ if (kbd) printk("unRaw "); +#ifdef CONFIG_VT if (tty) printk("saK "); +#endif printk("Boot " #ifdef CONFIG_APM "Off " diff -u --recursive --new-file v2.1.122/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.1.122/linux/drivers/char/tty_io.c Wed Aug 26 11:37:37 1998 +++ linux/drivers/char/tty_io.c Sat Sep 19 15:13:19 1998 @@ -126,11 +126,11 @@ static unsigned int tty_poll(struct file *, poll_table *); static int tty_open(struct inode *, struct file *); static int tty_release(struct inode *, struct file *); -static int tty_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg); +int tty_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg); static int tty_fasync(int fd, struct file * filp, int on); #ifdef CONFIG_8xx -extern long console_8xx_init(void); +extern long console_8xx_init(long, long); extern int rs_8xx_init(void); #endif /* CONFIG_8xx */ @@ -640,7 +640,13 @@ size_t count) { ssize_t ret = 0, written = 0; - + struct inode *inode = file->f_dentry->d_inode; + + up(&inode->i_sem); + if (down_interruptible(&inode->i_atomic_write)) { + down(&inode->i_sem); + return -ERESTARTSYS; + } for (;;) { unsigned long size = PAGE_SIZE*2; if (size > count) @@ -663,6 +669,8 @@ file->f_dentry->d_inode->i_mtime = CURRENT_TIME; ret = written; } + up(&inode->i_atomic_write); + down(&inode->i_sem); return ret; } @@ -1604,8 +1612,8 @@ /* * Split this up, as gcc can choke on it otherwise.. */ -static int tty_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg) +int tty_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) { struct tty_struct *tty, *real_tty; int retval; @@ -2004,7 +2012,11 @@ kmem_start = con_init(kmem_start); #endif #ifdef CONFIG_SERIAL_CONSOLE +#ifdef CONFIG_8xx + kmem_start = console_8xx_init(kmem_start, kmem_end); +#else kmem_start = serial_console_init(kmem_start, kmem_end); +#endif /* CONFIG_8xx */ #endif return kmem_start; } diff -u --recursive --new-file v2.1.122/linux/drivers/char/vt.c linux/drivers/char/vt.c --- v2.1.122/linux/drivers/char/vt.c Thu Aug 6 14:06:31 1998 +++ linux/drivers/char/vt.c Thu Sep 17 09:35:03 1998 @@ -74,45 +74,6 @@ #define GPNUM (GPLAST - GPFIRST + 1) /* - * This function is called when the size of the physical screen has been - * changed. If either the row or col argument is nonzero, set the appropriate - * entry in each winsize structure for all the virtual consoles, then - * send SIGWINCH to all processes with a virtual console as controlling - * tty. - */ - -static int -kd_size_changed(int row, int col) -{ - struct task_struct *p; - int i; - - if ( !row && !col ) return 0; - - for ( i = 0 ; i < MAX_NR_CONSOLES ; i++ ) - { - if ( console_driver.table[i] ) - { - if ( row ) console_driver.table[i]->winsize.ws_row = row; - if ( col ) console_driver.table[i]->winsize.ws_col = col; - } - } - - read_lock(&tasklist_lock); - for_each_task(p) - { - if ( p->tty && MAJOR(p->tty->device) == TTY_MAJOR && - MINOR(p->tty->device) <= MAX_NR_CONSOLES && MINOR(p->tty->device) ) - { - send_sig(SIGWINCH, p, 1); - } - } - read_unlock(&tasklist_lock); - - return 0; -} - -/* * Generates sound of some frequency for some number of clock ticks * * If freq is 0, will turn off sound, else will turn it on for that time. @@ -553,7 +514,7 @@ * explicitly blank/unblank the screen if switching modes */ if (arg == KD_TEXT) - do_unblank_screen(); + unblank_screen(); else do_blank_screen(1); return 0; @@ -781,7 +742,7 @@ if (arg == 0 || arg > MAX_NR_CONSOLES) return -ENXIO; arg--; - i = vc_allocate(arg, 0); + i = vc_allocate(arg); if (i) return i; set_console(arg); @@ -833,7 +794,7 @@ */ int newvt = vt_cons[console]->vt_newvt; vt_cons[console]->vt_newvt = -1; - i = vc_allocate(newvt, 0); + i = vc_allocate(newvt); if (i) return i; /* @@ -893,8 +854,7 @@ return i; __get_user(ll, &vtsizes->v_rows); __get_user(cc, &vtsizes->v_cols); - i = vc_resize_all(ll, cc); - return i ? i : kd_size_changed(ll, cc); + return vc_resize_all(ll, cc); } case VT_RESIZEX: @@ -942,12 +902,7 @@ if ( clin ) video_font_height = clin; - i = vc_resize_all(ll, cc); - if (i) - return i; - - kd_size_changed(ll, cc); - return 0; + return vc_resize_all(ll, cc); } case PIO_FONT: { @@ -1201,7 +1156,7 @@ * unblank the screen later. */ old_vc_mode = vt_cons[fg_console]->vc_mode; - update_screen(new_console); + switch_screen(new_console); /* * If this new console is under process control, send it a signal @@ -1239,14 +1194,10 @@ if (old_vc_mode != vt_cons[new_console]->vc_mode) { if (vt_cons[new_console]->vc_mode == KD_TEXT) - do_unblank_screen(); + unblank_screen(); else do_blank_screen(1); } - - /* Set the colour palette for this VT */ - if (vt_cons[new_console]->vc_mode == KD_TEXT) - set_palette() ; /* * Wake anyone waiting for their VT to activate diff -u --recursive --new-file v2.1.122/linux/drivers/net/ppp.c linux/drivers/net/ppp.c --- v2.1.122/linux/drivers/net/ppp.c Thu Aug 20 17:05:16 1998 +++ linux/drivers/net/ppp.c Tue Sep 22 21:52:33 1998 @@ -1386,6 +1386,7 @@ break; if (temp_i < PPP_MRU) temp_i = PPP_MRU; + ppp->mru = temp_i; if (ppp->flags & SC_DEBUG) printk(KERN_INFO "ppp_ioctl: set mru to %x\n", temp_i); diff -u --recursive --new-file v2.1.122/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c --- v2.1.122/linux/drivers/scsi/aic7xxx.c Thu Aug 6 14:06:32 1998 +++ linux/drivers/scsi/aic7xxx.c Sun Sep 20 16:21:05 1998 @@ -6791,6 +6791,7 @@ p->type = temp->type; p->unpause = temp->unpause; p->pause = temp->pause; + p->pdev = temp->pdev; p->pci_bus = temp->pci_bus; p->pci_device_fn = temp->pci_device_fn; p->bios_address = temp->bios_address; diff -u --recursive --new-file v2.1.122/linux/drivers/scsi/imm.c linux/drivers/scsi/imm.c --- v2.1.122/linux/drivers/scsi/imm.c Thu Sep 17 17:53:36 1998 +++ linux/drivers/scsi/imm.c Tue Sep 22 16:42:14 1998 @@ -65,8 +65,7 @@ #define IMM_BASE(x) imm_hosts[(x)].base -int base[NO_HOSTS] = -{0x03bc, 0x0378, 0x0278, 0x0000}; +int parbus_base[NO_HOSTS] = {0x03bc, 0x0378, 0x0278, 0x0000}; void imm_wakeup(void *ref) { diff -u --recursive --new-file v2.1.122/linux/drivers/scsi/ppa.c linux/drivers/scsi/ppa.c --- v2.1.122/linux/drivers/scsi/ppa.c Thu Sep 17 17:53:36 1998 +++ linux/drivers/scsi/ppa.c Sun Sep 20 18:00:15 1998 @@ -1027,6 +1027,7 @@ retv--; if (retv) + { if ((jiffies - tmp->jstart) > (1 * HZ)) { printk("ppa: Parallel port cable is unplugged!!\n"); ppa_fail(host_no, DID_BUS_BUSY); @@ -1035,6 +1036,7 @@ ppa_disconnect(host_no); return 1; /* Try again in a jiffy */ } + } cmd->SCp.phase++; } diff -u --recursive --new-file v2.1.122/linux/drivers/video/vgacon.c linux/drivers/video/vgacon.c --- v2.1.122/linux/drivers/video/vgacon.c Tue Aug 18 22:02:05 1998 +++ linux/drivers/video/vgacon.c Thu Sep 17 09:35:03 1998 @@ -64,8 +64,6 @@ */ #undef TRIDENT_GLITCH -#undef VGA_CAN_DO_64KB - #define dac_reg 0x3c8 #define dac_val 0x3c9 #define attrib_port 0x3c0 @@ -115,6 +113,7 @@ static int vga_is_gfx; static int vga_512_chars; static int vga_video_font_height; +static unsigned int vga_rolled_over = 0; void no_scroll(char *str, int *ints) @@ -190,7 +189,7 @@ display_desc = "*MDA"; request_region(0x3b0,12,"mda"); request_region(0x3bf, 1,"mda"); - vga_video_font_height = 16; + vga_video_font_height = 14; } } else /* If not, it is color. */ @@ -453,9 +452,8 @@ */ vga_video_num_columns = c->vc_cols; vga_video_num_lines = c->vc_rows; - if (vga_is_gfx) - return 1; - scr_memcpyw_to((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf, c->vc_screenbuf_size); + if (!vga_is_gfx) + scr_memcpyw_to((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf, c->vc_screenbuf_size); return 0; /* Redrawing not needed */ } @@ -474,8 +472,7 @@ static int vgacon_set_palette(struct vc_data *c, unsigned char *table) { #ifdef CAN_LOAD_PALETTE - - if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked) + if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked || !CON_IS_VISIBLE(c)) return -EINVAL; vga_set_palette(c, table); return 0; @@ -637,10 +634,11 @@ vga_palette_blanked = 1; return 0; } - scr_memsetw((void *)vga_vram_base, BLANK, vc_cons[0].d->vc_screenbuf_size); + vgacon_set_origin(c); + scr_memsetw((void *)vga_vram_base, BLANK, c->vc_screenbuf_size); return 1; case -1: /* Entering graphic mode */ - scr_memsetw((void *)vga_vram_base, BLANK, vc_cons[0].d->vc_screenbuf_size); + scr_memsetw((void *)vga_vram_base, BLANK, c->vc_screenbuf_size); vga_is_gfx = 1; return 1; default: /* VESA blanking */ @@ -899,14 +897,24 @@ if (!lines) /* Turn scrollback off */ c->vc_visible_origin = c->vc_origin; else { - int p = c->vc_visible_origin - vga_vram_base; - int margin = c->vc_rows/4 * c->vc_size_row; - p += lines * c->vc_size_row; - if (lines < 0 && p < margin) + int vram_size = vga_vram_end - vga_vram_base; + int margin = c->vc_size_row * 4; + int ul, we, p, st; + + if (vga_rolled_over > (c->vc_scr_end - vga_vram_base) + margin) { + ul = c->vc_scr_end - vga_vram_base; + we = vga_rolled_over + c->vc_size_row; + } else { + ul = 0; + we = vram_size; + } + p = (c->vc_visible_origin - vga_vram_base - ul + we) % we + lines * c->vc_size_row; + st = (c->vc_origin - vga_vram_base - ul + we) % we; + if (p < margin) p = 0; - c->vc_visible_origin = p + vga_vram_base; - if (lines > 0 && c->vc_visible_origin > c->vc_origin - margin) - c->vc_visible_origin = c->vc_origin; + if (p > st - margin) + p = st; + c->vc_visible_origin = vga_vram_base + (p + ul) % we; } vga_set_mem_top(c); return 1; @@ -919,6 +927,7 @@ return 0; c->vc_origin = c->vc_visible_origin = vga_vram_base; vga_set_mem_top(c); + vga_rolled_over = 0; return 1; } @@ -935,9 +944,8 @@ c->vc_x = ORIG_X; c->vc_y = ORIG_Y; } - if (vga_is_gfx) - return; - scr_memcpyw_from((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin, c->vc_screenbuf_size); + if (!vga_is_gfx) + scr_memcpyw_from((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin, c->vc_screenbuf_size); } static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, int lines) @@ -962,6 +970,7 @@ (u16 *)(oldo + delta), c->vc_screenbuf_size - delta); c->vc_origin = vga_vram_base; + vga_rolled_over = oldo - vga_vram_base; } else c->vc_origin += delta; scr_memsetw((u16 *)(c->vc_origin + c->vc_screenbuf_size - delta), c->vc_video_erase_char, delta); @@ -971,6 +980,7 @@ (u16 *)oldo, c->vc_screenbuf_size - delta); c->vc_origin = vga_vram_end - c->vc_screenbuf_size; + vga_rolled_over = 0; } else c->vc_origin -= delta; c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; diff -u --recursive --new-file v2.1.122/linux/fs/Config.in linux/fs/Config.in --- v2.1.122/linux/fs/Config.in Sat Sep 5 16:46:41 1998 +++ linux/fs/Config.in Sun Sep 20 23:23:47 1998 @@ -67,11 +67,9 @@ define_bool CONFIG_AMIGA_PARTITION y fi tristate 'UFS filesystem support' CONFIG_UFS_FS -if [ "$CONFIG_UFS_FS" != "n" ]; then - bool 'BSD disklabel (FreeBSD partition tables) support' CONFIG_BSD_DISKLABEL - bool 'SMD disklabel (Sun partition tables) support' CONFIG_SMD_DISKLABEL - bool 'Solaris (x86) partition table support' CONFIG_SOLARIS_X86_PARTITION -fi +bool 'BSD disklabel (BSD partition tables) support' CONFIG_BSD_DISKLABEL +bool 'SMD disklabel (Sun partition tables) support' CONFIG_SMD_DISKLABEL +bool 'Solaris (x86) partition table support' CONFIG_SOLARIS_X86_PARTITION if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then tristate '/dev/pts filesystem for Unix98 PTYs' CONFIG_DEVPTS_FS fi diff -u --recursive --new-file v2.1.122/linux/fs/affs/symlink.c linux/fs/affs/symlink.c --- v2.1.122/linux/fs/affs/symlink.c Mon Jan 12 14:46:24 1998 +++ linux/fs/affs/symlink.c Sat Sep 19 13:39:45 1998 @@ -20,7 +20,7 @@ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) static int affs_readlink(struct dentry *, char *, int); -static struct dentry *affs_follow_link(struct dentry *dentry, struct dentry *base); +static struct dentry *affs_follow_link(struct dentry *dentry, struct dentry *base, unsigned int); struct inode_operations affs_symlink_inode_operations = { NULL, /* no file-operations */ @@ -98,7 +98,7 @@ } static struct dentry * -affs_follow_link(struct dentry *dentry, struct dentry *base) +affs_follow_link(struct dentry *dentry, struct dentry *base, unsigned int follow) { struct inode *inode = dentry->d_inode; struct buffer_head *bh; @@ -150,7 +150,7 @@ } buffer[i] = '\0'; affs_brelse(bh); - base = lookup_dentry(buffer,base,1); + base = lookup_dentry(buffer,base,follow); kfree(buffer); return base; } diff -u --recursive --new-file v2.1.122/linux/fs/autofs/symlink.c linux/fs/autofs/symlink.c --- v2.1.122/linux/fs/autofs/symlink.c Sun Jan 4 00:53:43 1998 +++ linux/fs/autofs/symlink.c Sat Sep 19 13:41:02 1998 @@ -27,12 +27,13 @@ } static struct dentry * autofs_follow_link(struct dentry *dentry, - struct dentry *base) + struct dentry *base, + unsigned int follow) { struct autofs_symlink *sl; sl = (struct autofs_symlink *)dentry->d_inode->u.generic_ip; - return lookup_dentry(sl->data, base, 1); + return lookup_dentry(sl->data, base, follow); } struct inode_operations autofs_symlink_inode_operations = { diff -u --recursive --new-file v2.1.122/linux/fs/bad_inode.c linux/fs/bad_inode.c --- v2.1.122/linux/fs/bad_inode.c Wed Aug 26 11:37:40 1998 +++ linux/fs/bad_inode.c Mon Sep 21 14:37:20 1998 @@ -15,7 +15,7 @@ * so that a bad root inode can at least be unmounted. To do this * we must dput() the base and return the dentry with a dget(). */ -static struct dentry * bad_follow_link(struct dentry *dent, struct dentry *base) +static struct dentry * bad_follow_link(struct dentry *dent, struct dentry *base, unsigned int follow) { dput(base); return dget(dent); diff -u --recursive --new-file v2.1.122/linux/fs/coda/symlink.c linux/fs/coda/symlink.c --- v2.1.122/linux/fs/coda/symlink.c Thu May 7 22:51:53 1998 +++ linux/fs/coda/symlink.c Sat Sep 19 13:41:28 1998 @@ -26,7 +26,7 @@ #include static int coda_readlink(struct dentry *de, char *buffer, int length); -static struct dentry *coda_follow_link(struct dentry *, struct dentry *); +static struct dentry *coda_follow_link(struct dentry *, struct dentry *, unsigned int); struct inode_operations coda_symlink_inode_operations = { NULL, /* no file-operations */ @@ -86,7 +86,8 @@ } static struct dentry *coda_follow_link(struct dentry *de, - struct dentry *base) + struct dentry *base, + unsigned int follow) { struct inode *inode = de->d_inode; int error; @@ -116,7 +117,7 @@ memcpy(path, mem, len); path[len] = 0; - base = lookup_dentry(path, base, 1); + base = lookup_dentry(path, base, follow); kfree(path); return base; } diff -u --recursive --new-file v2.1.122/linux/fs/dquot.c linux/fs/dquot.c --- v2.1.122/linux/fs/dquot.c Wed Aug 26 11:37:40 1998 +++ linux/fs/dquot.c Fri Sep 25 16:24:56 1998 @@ -18,6 +18,9 @@ * * Fixes: Dmitry Gorodchanin , 11 Feb 96 * + * Revised list management to avoid races + * -- Bill Hawes, , 9/98 + * * (C) Copyright 1994 - 1997 Marco van Wieringen */ @@ -50,12 +53,29 @@ static kmem_cache_t *dquot_cachep; -static struct dquot *dquot_hash[NR_DQHASH]; -static struct free_dquot_queue { - struct dquot *head; - struct dquot **last; -} free_dquots = { NULL, &free_dquots.head }; +/* + * Dquot List Management: + * The quota code uses three lists for dquot management: the inuse_list, + * free_dquots, and dquot_hash[] array. A single dquot structure may be + * on all three lists, depending on its current state. + * + * All dquots are placed on the inuse_list when first created, and this + * list is used for the sync and invalidate operations, which must look + * at every dquot. + * + * Unused dquots (dq_count == 0) are added to the free_dquots list when + * freed, and this list is searched whenever we need an available dquot. + * Dquots are removed from the list as soon as they are used again, and + * nr_free_dquots gives the number of dquots on the list. + * + * Dquots with a specific identity (device, type and id) are placed on + * one of the dquot_hash[] hash chains. The provides an efficient search + * mechanism to lcoate a specific dquot. + */ + static struct dquot *inuse_list = NULL; +LIST_HEAD(free_dquots); +static struct dquot *dquot_hash[NR_DQHASH]; static int dquot_updating[NR_DQHASH]; static struct dqstats dqstats; @@ -128,37 +148,29 @@ return dquot; } +/* Add a dquot to the head of the free list */ static inline void put_dquot_head(struct dquot *dquot) { - if ((dquot->dq_next = free_dquots.head) != NULL) - free_dquots.head->dq_pprev = &dquot->dq_next; - else - free_dquots.last = &dquot->dq_next; - free_dquots.head = dquot; - dquot->dq_pprev = &free_dquots.head; + list_add(&dquot->dq_free, &free_dquots); nr_free_dquots++; } +/* Add a dquot to the tail of the free list */ static inline void put_dquot_last(struct dquot *dquot) { - dquot->dq_next = NULL; - dquot->dq_pprev = free_dquots.last; - *free_dquots.last = dquot; - free_dquots.last = &dquot->dq_next; + list_add(&dquot->dq_free, free_dquots.prev); nr_free_dquots++; } static inline void remove_free_dquot(struct dquot *dquot) { - if (dquot->dq_pprev) { - if (dquot->dq_next) - dquot->dq_next->dq_pprev = dquot->dq_pprev; - else - free_dquots.last = dquot->dq_pprev; - *dquot->dq_pprev = dquot->dq_next; - dquot->dq_pprev = NULL; - nr_free_dquots--; - } + /* sanity check */ + if (list_empty(&dquot->dq_free)) { + printk("remove_free_dquot: dquot not on free list??\n"); + } + list_del(&dquot->dq_free); + INIT_LIST_HEAD(&dquot->dq_free); + nr_free_dquots--; } static inline void put_inuse(struct dquot *dquot) @@ -169,6 +181,7 @@ dquot->dq_pprev = &inuse_list; } +#if 0 /* currently not needed */ static inline void remove_inuse(struct dquot *dquot) { if (dquot->dq_pprev) { @@ -178,6 +191,7 @@ dquot->dq_pprev = NULL; } } +#endif static void __wait_on_dquot(struct dquot *dquot) { @@ -187,7 +201,6 @@ repeat: current->state = TASK_UNINTERRUPTIBLE; if (dquot->dq_flags & DQ_LOCKED) { - dquot->dq_flags |= DQ_WANT; schedule(); goto repeat; } @@ -210,24 +223,16 @@ static inline void unlock_dquot(struct dquot *dquot) { dquot->dq_flags &= ~DQ_LOCKED; - if (dquot->dq_flags & DQ_WANT) { - dquot->dq_flags &= ~DQ_WANT; - wake_up(&dquot->dq_wait); - } + wake_up(&dquot->dq_wait); } static void write_dquot(struct dquot *dquot) { - short type; - struct file *filp; + short type = dquot->dq_type; + struct file *filp = dquot->dq_mnt->mnt_dquot.files[type]; mm_segment_t fs; loff_t offset; - - type = dquot->dq_type; - filp = dquot->dq_mnt->mnt_dquot.files[type]; - - if (!(dquot->dq_flags & DQ_MOD) || (filp == (struct file *)NULL)) - return; + ssize_t ret; lock_dquot(dquot); down(&dquot->dq_mnt->mnt_dquot.semaphore); @@ -235,8 +240,18 @@ fs = get_fs(); set_fs(KERNEL_DS); - if (filp->f_op->write(filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk), &offset) == sizeof(struct dqblk)) - dquot->dq_flags &= ~DQ_MOD; + /* + * Note: clear the DQ_MOD flag unconditionally, + * so we don't loop forever on failure. + */ + dquot->dq_flags &= ~DQ_MOD; + ret = 0; + if (filp) + ret = filp->f_op->write(filp, (char *)&dquot->dq_dqb, + sizeof(struct dqblk), &offset); + if (ret != sizeof(struct dqblk)) + printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", + kdevname(dquot->dq_dev)); up(&dquot->dq_mnt->mnt_dquot.semaphore); set_fs(fs); @@ -274,73 +289,86 @@ dqstats.reads++; } +/* + * Unhash and selectively clear the dquot structure, + * but preserve the use count, list pointers, and + * wait queue. + */ void clear_dquot(struct dquot *dquot) { - struct wait_queue *wait; - - /* So we don't disappear. */ - dquot->dq_count++; - - wait_on_dquot(dquot); - - if (--dquot->dq_count > 0) - remove_inuse(dquot); - else - remove_free_dquot(dquot); + /* unhash it first */ unhash_dquot(dquot); - wait = dquot->dq_wait; - memset(dquot, 0, sizeof(*dquot)); barrier(); - dquot->dq_wait = wait; - put_dquot_head(dquot); + dquot->dq_mnt = NULL; + dquot->dq_flags = 0; + dquot->dq_referenced = 0; + memset(&dquot->dq_dqb, 0, sizeof(struct dqblk)); } void invalidate_dquots(kdev_t dev, short type) { - struct dquot *dquot, *next = NULL; - int pass = 0; + struct dquot *dquot, *next = inuse_list; + int need_restart; - dquot = free_dquots.head; -repeat: - while (dquot) { +restart: + need_restart = 0; + while ((dquot = next) != NULL) { next = dquot->dq_next; - if (dquot->dq_dev != dev || dquot->dq_type != type) - goto next; - clear_dquot(dquot); - next: - dquot = next; - } + if (dquot->dq_dev != dev) + continue; + if (dquot->dq_type != type) + continue; + if (dquot->dq_flags & DQ_LOCKED) { + __wait_on_dquot(dquot); - if (pass == 0) { - dquot = inuse_list; - pass = 1; - goto repeat; + /* Set the flag for another pass. */ + need_restart = 1; + /* + * Make sure it's still the same dquot. + */ + if (dquot->dq_dev != dev) + continue; + if (dquot->dq_type != type) + continue; + } + clear_dquot(dquot); } + /* + * If anything blocked, restart the operation + * to ensure we don't miss any dquots. + */ + if (need_restart) + goto restart; } int sync_dquots(kdev_t dev, short type) { - struct dquot *dquot, *next; - int pass = 0; + struct dquot *dquot, *next = inuse_list; + int need_restart; - dquot = free_dquots.head; -repeat: - while (dquot) { +restart: + need_restart = 0; + while ((dquot = next) != NULL) { next = dquot->dq_next; - if ((dev && dquot->dq_dev != dev) || - (type != -1 && dquot->dq_type != type)) - goto next; + if (dev && dquot->dq_dev != dev) + continue; + if (type != -1 && dquot->dq_type != type) + continue; + if (!(dquot->dq_flags & (DQ_LOCKED | DQ_MOD))) + continue; + wait_on_dquot(dquot); if (dquot->dq_flags & DQ_MOD) write_dquot(dquot); - next: - dquot = next; + /* Set the flag for another pass. */ + need_restart = 1; } + /* + * If anything blocked, restart the operation + * to ensure we don't miss any dquots. + */ + if (need_restart) + goto restart; - if (pass == 0) { - dquot = inuse_list; - pass = 1; - goto repeat; - } dqstats.syncs++; return(0); } @@ -349,40 +377,41 @@ { if (!dquot) return; + if (!dquot->dq_count) { + printk("VFS: dqput: trying to free free dquot\n"); + printk("VFS: device %s, dquot of %s %d\n", + kdevname(dquot->dq_dev), quotatypes[dquot->dq_type], + dquot->dq_id); + return; + } /* * If the dq_mnt pointer isn't initialized this entry needs no - * checking and doesn't need to be written. It just an empty + * checking and doesn't need to be written. It's just an empty * dquot that is put back on to the freelist. */ if (dquot->dq_mnt != (struct vfsmount *)NULL) { dqstats.drops++; - wait_on_dquot(dquot); - - if (!dquot->dq_count) { - printk("VFS: dqput: trying to free free dquot\n"); - printk("VFS: device %s, dquot of %s %d\n", kdevname(dquot->dq_dev), - quotatypes[dquot->dq_type], dquot->dq_id); - return; - } we_slept: + wait_on_dquot(dquot); if (dquot->dq_count > 1) { dquot->dq_count--; return; - } else { - wake_up(&dquot_wait); - - if (dquot->dq_flags & DQ_MOD) { - write_dquot(dquot); - wait_on_dquot(dquot); - goto we_slept; - } + } + if (dquot->dq_flags & DQ_MOD) { + write_dquot(dquot); + goto we_slept; } } + /* sanity check */ + if (!list_empty(&dquot->dq_free)) { + printk("dqput: dquot already on free list??\n"); + } if (--dquot->dq_count == 0) { - remove_inuse(dquot); - put_dquot_last(dquot); /* Place at end of LRU free queue */ + /* Place at end of LRU free queue */ + put_dquot_last(dquot); + wake_up(&dquot_wait); } return; @@ -400,45 +429,43 @@ nr_dquots++; memset((caddr_t)dquot, 0, sizeof(struct dquot)); + /* all dquots go on the inuse_list */ + put_inuse(dquot); put_dquot_head(dquot); cnt--; } } -static struct dquot *find_best_candidate_weighted(struct dquot *dquot) +static struct dquot *find_best_candidate_weighted(void) { - int limit, myscore; - unsigned long bestscore; - struct dquot *best = NULL; - - if (dquot) { - bestscore = 2147483647; - limit = nr_free_dquots >> 2; - do { - if (!((dquot->dq_flags & DQ_LOCKED) || (dquot->dq_flags & DQ_MOD))) { - myscore = dquot->dq_referenced; - if (myscore < bestscore) { - bestscore = myscore; - best = dquot; - } - } - dquot = dquot->dq_next; - } while (dquot && --limit); + struct list_head *tmp = &free_dquots; + struct dquot *dquot, *best = NULL; + unsigned long myscore, bestscore = ~0U; + int limit = (nr_free_dquots > 128) ? nr_free_dquots >> 2 : 32; + + while ((tmp = tmp->next) != &free_dquots && --limit) { + dquot = list_entry(tmp, struct dquot, dq_free); + if (dquot->dq_flags & (DQ_LOCKED | DQ_MOD)) + continue; + myscore = dquot->dq_referenced; + if (myscore < bestscore) { + bestscore = myscore; + best = dquot; + } } return best; } -static inline struct dquot *find_best_free(struct dquot *dquot) +static inline struct dquot *find_best_free(void) { - int limit; + struct list_head *tmp = &free_dquots; + struct dquot *dquot; + int limit = (nr_free_dquots > 1024) ? nr_free_dquots >> 5 : 32; - if (dquot) { - limit = nr_free_dquots >> 5; - do { - if (dquot->dq_referenced == 0) - return dquot; - dquot = dquot->dq_next; - } while (dquot && --limit); + while ((tmp = tmp->next) != &free_dquots && --limit) { + dquot = list_entry(tmp, struct dquot, dq_free); + if (dquot->dq_referenced == 0) + return dquot; } return NULL; } @@ -446,42 +473,56 @@ struct dquot *get_empty_dquot(void) { struct dquot *dquot; + int count; repeat: - dquot = find_best_free(free_dquots.head); + dquot = find_best_free(); if (!dquot) goto pressure; got_it: - dquot->dq_count++; - wait_on_dquot(dquot); - unhash_dquot(dquot); - remove_free_dquot(dquot); + if (dquot->dq_flags & (DQ_LOCKED | DQ_MOD)) { + wait_on_dquot(dquot); + if (dquot->dq_flags & DQ_MOD) + write_dquot(dquot); + /* + * The dquot may be back in use now, so we + * must recheck the free list. + */ + goto repeat; + } + /* sanity check ... */ + if (dquot->dq_count != 0) + printk(KERN_ERR "VFS: free dquot count=%d\n", dquot->dq_count); - memset(dquot, 0, sizeof(*dquot)); + remove_free_dquot(dquot); dquot->dq_count = 1; - - put_inuse(dquot); + /* unhash and selectively clear the structure */ + clear_dquot(dquot); return dquot; + pressure: if (nr_dquots < max_dquots) { grow_dquots(); goto repeat; } - dquot = find_best_candidate_weighted(free_dquots.head); - if (!dquot) { - printk("VFS: No free dquots, contact mvw@planets.elm.net\n"); - sleep_on(&dquot_wait); - goto repeat; - } - if (dquot->dq_flags & DQ_LOCKED) { - wait_on_dquot(dquot); - goto repeat; - } else if (dquot->dq_flags & DQ_MOD) { - write_dquot(dquot); + dquot = find_best_candidate_weighted(); + if (dquot) + goto got_it; + /* + * Try pruning the dcache to free up some dquots ... + */ + count = select_dcache(128, 0); + if (count) { + printk(KERN_DEBUG "get_empty_dquot: pruning %d\n", count); + prune_dcache(count); + free_inode_memory(count); goto repeat; } - goto got_it; + + printk("VFS: No free dquots, contact mvw@planets.elm.net\n"); + sleep_on(&dquot_wait); + goto repeat; } struct dquot *dqget(kdev_t dev, unsigned int id, short type) @@ -507,12 +548,12 @@ dquot->dq_type = type; dquot->dq_dev = dev; dquot->dq_mnt = vfsmnt; - read_dquot(dquot); + /* hash it first so it can be found */ hash_dquot(dquot); + read_dquot(dquot); } else { if (!dquot->dq_count++) { remove_free_dquot(dquot); - put_inuse(dquot); } else dqstats.cache_hits++; wait_on_dquot(dquot); @@ -546,6 +587,7 @@ inode = filp->f_dentry->d_inode; if (!inode) continue; + /* N.B. race problem -- filp could become unused */ if (filp->f_mode & FMODE_WRITE) { sb->dq_op->initialize(inode, type); inode->i_flags |= S_QUOTA; @@ -558,10 +600,16 @@ struct super_block *sb = get_super(dev); struct file *filp; struct inode *inode; + struct dquot *dquot; + int cnt; if (!sb || !sb->dq_op) return; /* nothing to do */ +restart: + /* free any quota for unused dentries */ + shrink_dcache_sb(sb); + for (filp = inuse_filps; filp; filp = filp->f_next) { if (!filp->f_dentry) continue; @@ -570,10 +618,25 @@ inode = filp->f_dentry->d_inode; if (!inode) continue; + /* + * Note: we restart after each blocking operation, + * as the inuse_filps list may have changed. + */ if (IS_QUOTAINIT(inode)) { - sb->dq_op->drop(inode); + dquot = inode->i_dquot[type]; inode->i_dquot[type] = NODQUOT; + /* any other quota in use? */ + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + if (inode->i_dquot[cnt] != NODQUOT) + goto put_it; + } inode->i_flags &= ~S_QUOTA; + put_it: + if (dquot != NODQUOT) { + dqput(dquot); + /* we may have blocked ... */ + goto restart; + } } } } @@ -638,7 +701,8 @@ return(initiator == 0 && dquot->dq_mnt->mnt_dquot.rsquash[dquot->dq_type] == 0); } -static int check_idq(struct dquot *dquot, short type, u_long short inodes, uid_t initiator, struct tty_struct *tty) +static int check_idq(struct dquot *dquot, short type, u_long short inodes, uid_t initiator, + struct tty_struct *tty) { if (inodes <= 0 || dquot->dq_flags & DQ_FAKE) return(QUOTA_OK); @@ -682,7 +746,8 @@ return(QUOTA_OK); } -static int check_bdq(struct dquot *dquot, short type, u_long blocks, uid_t initiator, struct tty_struct *tty, char warn) +static int check_bdq(struct dquot *dquot, short type, u_long blocks, uid_t initiator, + struct tty_struct *tty, char warn) { if (blocks <= 0 || dquot->dq_flags & DQ_FAKE) return(QUOTA_OK); @@ -732,15 +797,15 @@ */ static int set_dqblk(kdev_t dev, int id, short type, int flags, struct dqblk *dqblk) { - int error; struct dquot *dquot; + int error = -EFAULT; struct dqblk dq_dqblk; if (dqblk == (struct dqblk *)NULL) - return(-EFAULT); + return error; if (flags & QUOTA_SYSCALL) { - if ((error = copy_from_user((caddr_t)&dq_dqblk, (caddr_t)dqblk, sizeof(struct dqblk))) != 0) + if (copy_from_user(&dq_dqblk, dqblk, sizeof(struct dqblk))) return(error); } else memcpy((caddr_t)&dq_dqblk, (caddr_t)dqblk, sizeof(struct dqblk)); @@ -793,26 +858,35 @@ static int get_quota(kdev_t dev, int id, short type, struct dqblk *dqblk) { struct dquot *dquot; - int error; + int error = -ESRCH; - if (dev_has_quota_enabled(dev, type)) { - if (dqblk == (struct dqblk *)NULL) - return(-EFAULT); - - if ((dquot = dqget(dev, id, type)) != NODQUOT) { - error = copy_to_user((caddr_t)dqblk, (caddr_t)&dquot->dq_dqb, sizeof(struct dqblk)); - dqput(dquot); - return(error); - } - } - return(-ESRCH); + if (!dev_has_quota_enabled(dev, type)) + goto out; + dquot = dqget(dev, id, type); + if (dquot == NODQUOT) + goto out; + + error = -EFAULT; + if (dqblk && !copy_to_user(dqblk, &dquot->dq_dqb, sizeof(struct dqblk))) + error = 0; + dqput(dquot); +out: + return error; } static int get_stats(caddr_t addr) { + int error = -EFAULT; + struct dqstats stats; + dqstats.allocated_dquots = nr_dquots; dqstats.free_dquots = nr_free_dquots; - return(copy_to_user(addr, (caddr_t)&dqstats, sizeof(struct dqstats))); + + /* make a copy, in case we page-fault in user space */ + memcpy(&stats, &dqstats, sizeof(struct dqstats)); + if (!copy_to_user(addr, &stats, sizeof(struct dqstats))) + error = 0; + return error; } static int quota_root_squash(kdev_t dev, short type, int *addr) @@ -823,11 +897,12 @@ if ((vfsmnt = lookup_vfsmnt(dev)) == (struct vfsmount *)NULL) return(-ENODEV); - if ((error = copy_from_user((caddr_t)&new_value, (caddr_t)addr, sizeof(int))) != 0) - return(error); - - vfsmnt->mnt_dquot.rsquash[type] = new_value; - return(0); + error = -EFAULT; + if (!copy_from_user(&new_value, addr, sizeof(int))) { + vfsmnt->mnt_dquot.rsquash[type] = new_value; + error = 0; + } + return error; } /* @@ -856,6 +931,8 @@ /* * Externally referenced functions through dquot_operations in inode. + * + * Note: this is a blocking operation. */ void dquot_initialize(struct inode *inode, short type) { @@ -894,6 +971,11 @@ } } +/* + * Release all quota for the specified inode. + * + * Note: this is a blocking operation. + */ void dquot_drop(struct inode *inode) { struct dquot *dquot; @@ -909,7 +991,11 @@ } } -int dquot_alloc_block(const struct inode *inode, unsigned long number, uid_t initiator, char warn) +/* + * Note: this is a blocking operation. + */ +int dquot_alloc_block(const struct inode *inode, unsigned long number, uid_t initiator, + char warn) { unsigned short cnt; struct tty_struct *tty = current->tty; @@ -930,6 +1016,9 @@ return(QUOTA_OK); } +/* + * Note: this is a blocking operation. + */ int dquot_alloc_inode(const struct inode *inode, unsigned long number, uid_t initiator) { unsigned short cnt; @@ -951,6 +1040,9 @@ return(QUOTA_OK); } +/* + * Note: this is a blocking operation. + */ void dquot_free_block(const struct inode *inode, unsigned long number) { unsigned short cnt; @@ -962,6 +1054,9 @@ } } +/* + * Note: this is a blocking operation. + */ void dquot_free_inode(const struct inode *inode, unsigned long number) { unsigned short cnt; @@ -975,6 +1070,8 @@ /* * Transfer the number of inode and blocks from one diskquota to an other. + * + * Note: this is a blocking operation. */ int dquot_transfer(struct inode *inode, struct iattr *iattr, char direction, uid_t initiator) { @@ -1029,8 +1126,8 @@ } /* - * Finally perform the needed transfer from transfer_from to transfer_to. - * And release any pointer to dquots not needed anymore. + * Finally perform the needed transfer from transfer_from to transfer_to, + * and release any pointers to dquots not needed anymore. */ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { /* @@ -1050,9 +1147,10 @@ } if (inode->i_dquot[cnt] != NODQUOT) { - dqput(transfer_from[cnt]); - dqput(inode->i_dquot[cnt]); + struct dquot *temp = inode->i_dquot[cnt]; inode->i_dquot[cnt] = transfer_to[cnt]; + dqput(temp); + dqput(transfer_from[cnt]); } else { dqput(transfer_from[cnt]); dqput(transfer_to[cnt]); @@ -1082,8 +1180,8 @@ * Definitions of diskquota operations. */ struct dquot_operations dquot_operations = { - dquot_initialize, - dquot_drop, + dquot_initialize, /* mandatory */ + dquot_drop, /* mandatory */ dquot_alloc_block, dquot_alloc_inode, dquot_free_block, @@ -1121,30 +1219,47 @@ int quota_off(kdev_t dev, short type) { struct vfsmount *vfsmnt; + struct file *filp; short cnt; for (cnt = 0; cnt < MAXQUOTAS; cnt++) { if (type != -1 && cnt != type) continue; - if ((vfsmnt = lookup_vfsmnt(dev)) == (struct vfsmount *)NULL || - is_enabled(vfsmnt, cnt) == 0 || - vfsmnt->mnt_sb == (struct super_block *)NULL) + vfsmnt = lookup_vfsmnt(dev); + if (!vfsmnt) + goto out; + if (!vfsmnt->mnt_sb) + goto out; + if (!is_enabled(vfsmnt, cnt)) continue; + reset_enable_flags(vfsmnt, cnt); - vfsmnt->mnt_sb->dq_op = (struct dquot_operations *)NULL; - + /* Note: these are blocking operations */ reset_dquot_ptrs(dev, cnt); invalidate_dquots(dev, cnt); - fput(vfsmnt->mnt_dquot.files[cnt]); - - reset_enable_flags(vfsmnt, cnt); + filp = vfsmnt->mnt_dquot.files[cnt]; vfsmnt->mnt_dquot.files[cnt] = (struct file *)NULL; vfsmnt->mnt_dquot.inode_expire[cnt] = 0; vfsmnt->mnt_dquot.block_expire[cnt] = 0; + fput(filp); + } + + /* + * Check whether any quota is still enabled, + * and if not clear the dq_op pointer. + */ + vfsmnt = lookup_vfsmnt(dev); + if (vfsmnt && vfsmnt->mnt_sb) { + int enabled = 0; + for (cnt = 0; cnt < MAXQUOTAS; cnt++) + enabled |= is_enabled(vfsmnt, cnt); + if (!enabled) + vfsmnt->mnt_sb->dq_op = NULL; } +out: return(0); } @@ -1316,10 +1431,9 @@ flags |= QUOTA_SYSCALL; + ret = -ESRCH; if (dev_has_quota_enabled(dev, type)) ret = set_dqblk(dev, id, type, flags, (struct dqblk *) addr); - else - ret = -ESRCH; out: unlock_kernel(); return ret; diff -u --recursive --new-file v2.1.122/linux/fs/ext2/balloc.c linux/fs/ext2/balloc.c --- v2.1.122/linux/fs/ext2/balloc.c Wed Aug 26 11:37:40 1998 +++ linux/fs/ext2/balloc.c Fri Sep 25 23:02:42 1998 @@ -686,6 +686,12 @@ } } +int ext2_group_sparse(int group) +{ + return (test_root(group, 3) || test_root(group, 5) || + test_root(group, 7)); +} + void ext2_check_blocks_bitmap (struct super_block * sb) { struct buffer_head * bh; @@ -716,7 +722,7 @@ if (!(le32_to_cpu(sb->u.ext2_sb.s_feature_ro_compat) & EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) || - (test_root(i, 3) || test_root(i, 5) || test_root(i, 7))) { + ext2_group_sparse(i)) { if (!ext2_test_bit (0, bh->b_data)) ext2_error (sb, "ext2_check_blocks_bitmap", "Superblock in group %d " diff -u --recursive --new-file v2.1.122/linux/fs/ext2/super.c linux/fs/ext2/super.c --- v2.1.122/linux/fs/ext2/super.c Mon Apr 6 17:41:00 1998 +++ linux/fs/ext2/super.c Fri Sep 25 23:02:42 1998 @@ -764,8 +764,8 @@ int ext2_statfs (struct super_block * sb, struct statfs * buf, int bufsiz) { unsigned long overhead; - unsigned long overhead_per_group; struct statfs tmp; + int ngroups, i; if (test_opt (sb, MINIX_DF)) overhead = 0; @@ -773,13 +773,35 @@ /* * Compute the overhead (FS structures) */ - overhead_per_group = 1 /* super block */ + - sb->u.ext2_sb.s_db_per_group /* descriptors */ + - 1 /* block bitmap */ + - 1 /* inode bitmap */ + - sb->u.ext2_sb.s_itb_per_group /* inode table */; - overhead = le32_to_cpu(sb->u.ext2_sb.s_es->s_first_data_block) + - sb->u.ext2_sb.s_groups_count * overhead_per_group; + + /* + * All of the blocks before first_data_block are + * overhead + */ + overhead = le32_to_cpu(sb->u.ext2_sb.s_es->s_first_data_block); + + /* + * Add the overhead attributed to the superblock and + * block group descriptors. If this is sparse + * superblocks is turned on, then not all groups have + * this. + */ + if (le32_to_cpu(sb->u.ext2_sb.s_feature_ro_compat) & + EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) { + ngroups = 0; + for (i=0 ; i < sb->u.ext2_sb.s_groups_count; i++) + if (ext2_group_sparse(i)) + ngroups++; + } else + ngroups = sb->u.ext2_sb.s_groups_count; + overhead += ngroups * (1 + sb->u.ext2_sb.s_db_per_group); + + /* + * Every block group has an inode bitmap, a block + * bitmap, and an inode table. + */ + overhead += (sb->u.ext2_sb.s_groups_count * + (2 + sb->u.ext2_sb.s_itb_per_group)); } tmp.f_type = EXT2_SUPER_MAGIC; diff -u --recursive --new-file v2.1.122/linux/fs/ext2/symlink.c linux/fs/ext2/symlink.c --- v2.1.122/linux/fs/ext2/symlink.c Sun Jan 4 00:53:41 1998 +++ linux/fs/ext2/symlink.c Sat Sep 19 13:38:18 1998 @@ -25,7 +25,7 @@ #include static int ext2_readlink (struct dentry *, char *, int); -static struct dentry *ext2_follow_link(struct dentry *, struct dentry *); +static struct dentry *ext2_follow_link(struct dentry *, struct dentry *, unsigned int); /* * symlinks can't do much... @@ -52,7 +52,8 @@ }; static struct dentry * ext2_follow_link(struct dentry * dentry, - struct dentry *base) + struct dentry *base, + unsigned int follow) { struct inode *inode = dentry->d_inode; struct buffer_head * bh = NULL; @@ -68,7 +69,7 @@ link = bh->b_data; } UPDATE_ATIME(inode); - base = lookup_dentry(link, base, 1); + base = lookup_dentry(link, base, follow); if (bh) brelse(bh); return base; diff -u --recursive --new-file v2.1.122/linux/fs/inode.c linux/fs/inode.c --- v2.1.122/linux/fs/inode.c Wed Sep 9 14:51:09 1998 +++ linux/fs/inode.c Sat Sep 19 15:13:19 1998 @@ -131,6 +131,7 @@ INIT_LIST_HEAD(&inode->i_hash); INIT_LIST_HEAD(&inode->i_dentry); sema_init(&inode->i_sem, 1); + sema_init(&inode->i_atomic_write, 1); } static inline void write_inode(struct inode *inode) @@ -714,8 +715,11 @@ printk(KERN_ERR "iput: device %s inode %ld count changed, count=%d\n", kdevname(inode->i_dev), inode->i_ino, inode->i_count); if (atomic_read(&inode->i_sem.count) != 1) -printk(KERN_ERR "iput: Aieee, semaphore in use device %s, count=%d\n", -kdevname(inode->i_dev), atomic_read(&inode->i_sem.count)); +printk(KERN_ERR "iput: Aieee, semaphore in use inode %s/%ld, count=%d\n", +kdevname(inode->i_dev), inode->i_ino, atomic_read(&inode->i_sem.count)); +if (atomic_read(&inode->i_atomic_write.count) != 1) +printk(KERN_ERR "iput: Aieee, atomic write semaphore in use inode %s/%ld, count=%d\n", +kdevname(inode->i_dev), inode->i_ino, atomic_read(&inode->i_sem.count)); #endif } if (inode->i_count > (1<<31)) { diff -u --recursive --new-file v2.1.122/linux/fs/isofs/inode.c linux/fs/isofs/inode.c --- v2.1.122/linux/fs/isofs/inode.c Thu Sep 17 17:53:37 1998 +++ linux/fs/isofs/inode.c Fri Sep 25 16:27:13 1998 @@ -445,25 +445,31 @@ return vol_desc_start; } +/* + * Initialize the superblock and read the root inode. + * + * Note: a check_disk_change() has been done immediately prior + * to this call, so we don't need to check again. + */ struct super_block *isofs_read_super(struct super_block *s, void *data, int silent) { - struct buffer_head * bh = NULL, *pri_bh = NULL; - unsigned int blocksize; - unsigned int blocksize_bits; kdev_t dev = s->s_dev; + struct buffer_head * bh = NULL, *pri_bh = NULL; struct hs_primary_descriptor * h_pri = NULL; struct iso_primary_descriptor * pri = NULL; struct iso_supplementary_descriptor *sec = NULL; struct iso_directory_record * rootp; + int joliet_level = 0; int high_sierra; int iso_blknum, block; - int joliet_level = 0; int orig_zonesize; + int table; + unsigned int blocksize, blocksize_bits; unsigned int vol_desc_start; + unsigned long first_data_zone; struct inode * inode; struct iso9660_options opt; - int table; MOD_INC_USE_COUNT; /* lock before any blocking operations */ @@ -592,7 +598,6 @@ root_found: brelse(pri_bh); - s->u.isofs_sb.s_joliet_level = joliet_level; if (joliet_level && opt.rock == 'n') { /* This is the case of Joliet with the norock mount flag. @@ -623,10 +628,7 @@ s->u.isofs_sb.s_ninodes = 0; /* No way to figure this out easily */ - /* RDE: convert log zone size to bit shift */ - orig_zonesize = s -> u.isofs_sb.s_log_zone_size; - /* * If the zone size is smaller than the hardware sector size, * this is a fatal error. This would occur if the disc drive @@ -637,6 +639,7 @@ if(blocksize != 0 && orig_zonesize < blocksize) goto out_bad_size; + /* RDE: convert log zone size to bit shift */ switch (s -> u.isofs_sb.s_log_zone_size) { case 512: s -> u.isofs_sb.s_log_zone_size = 9; break; case 1024: s -> u.isofs_sb.s_log_zone_size = 10; break; @@ -657,14 +660,15 @@ /* RDE: data zone now byte offset! */ - s->u.isofs_sb.s_firstdatazone = ((isonum_733 (rootp->extent) + - isonum_711 (rootp->ext_attr_length)) - << s -> u.isofs_sb.s_log_zone_size); + first_data_zone = ((isonum_733 (rootp->extent) + + isonum_711 (rootp->ext_attr_length)) + << s -> u.isofs_sb.s_log_zone_size); + s->u.isofs_sb.s_firstdatazone = first_data_zone; #ifndef BEQUIET printk(KERN_DEBUG "Max size:%ld Log zone size:%ld\n", s->u.isofs_sb.s_max_size, 1UL << s->u.isofs_sb.s_log_zone_size); - printk(KERN_DEBUG "First datazone:%ld Root inode number %d\n", + printk(KERN_DEBUG "First datazone:%ld Root inode number:%ld\n", s->u.isofs_sb.s_firstdatazone >> s -> u.isofs_sb.s_log_zone_size, s->u.isofs_sb.s_firstdatazone); if(high_sierra) @@ -672,6 +676,29 @@ #endif /* + * If the Joliet level is set, we _may_ decide to use the + * secondary descriptor, but can't be sure until after we + * read the root inode. But before reading the root inode + * we may need to change the device blocksize, and would + * rather release the old buffer first. So, we cache the + * first_data_zone value from the secondary descriptor. + */ + if (joliet_level) { + pri = (struct iso_primary_descriptor *) sec; + rootp = (struct iso_directory_record *) + pri->root_directory_record; + first_data_zone = ((isonum_733 (rootp->extent) + + isonum_711 (rootp->ext_attr_length)) + << s -> u.isofs_sb.s_log_zone_size); + } + + /* + * We're all done using the volume descriptor, and may need + * to change the device blocksize, so release the buffer now. + */ + brelse(bh); + + /* * Force the blocksize to 512 for 512 byte sectors. The file * read primitives really get it wrong in a bad way if we don't * do this. @@ -688,22 +715,15 @@ * entries. By forcing the blocksize in this way, we ensure * that we will never be required to do this. */ - if( orig_zonesize != opt.blocksize ) - { - opt.blocksize = orig_zonesize; - blocksize_bits = 0; - { - int i = opt.blocksize; - while (i != 1){ - blocksize_bits++; - i >>=1; - } - } - set_blocksize(dev, opt.blocksize); + if ( orig_zonesize != opt.blocksize ) { + set_blocksize(dev, orig_zonesize); #ifndef BEQUIET - printk(KERN_DEBUG "Forcing new log zone size:%d\n", opt.blocksize); + printk(KERN_DEBUG + "ISOFS: Forcing new log zone size:%d\n", orig_zonesize); #endif - } + } + s->s_blocksize = orig_zonesize; + s->s_blocksize_bits = s -> u.isofs_sb.s_log_zone_size; s->u.isofs_sb.s_nls_iocharset = NULL; @@ -732,8 +752,12 @@ * as suid, so we merely allow them to set the default permissions. */ s->u.isofs_sb.s_mode = opt.mode & 0777; - s->s_blocksize = opt.blocksize; - s->s_blocksize_bits = blocksize_bits; + + /* + * Read the root inode, which _may_ result in changing + * the s_rock flag. Once we have the final s_rock value, + * we then decide whether to use the Joliet descriptor. + */ inode = iget(s, s->u.isofs_sb.s_firstdatazone); /* @@ -744,21 +768,17 @@ * CD with Unicode names. Until someone sees such a beast, it * will not be supported. */ - if (opt.rock == 'y' && s->u.isofs_sb.s_rock == 1) { + if (s->u.isofs_sb.s_rock == 1) { joliet_level = 0; - } - if (joliet_level) { - iput(inode); - pri = (struct iso_primary_descriptor *) sec; - rootp = (struct iso_directory_record *) - pri->root_directory_record; - s->u.isofs_sb.s_firstdatazone = - ((isonum_733 (rootp->extent) + - isonum_711 (rootp->ext_attr_length)) - << s -> u.isofs_sb.s_log_zone_size); - inode = iget(s, s->u.isofs_sb.s_firstdatazone); + } else if (joliet_level) { s->u.isofs_sb.s_rock = 0; - opt.rock = 'n'; + if (s->u.isofs_sb.s_firstdatazone != first_data_zone) { + s->u.isofs_sb.s_firstdatazone = first_data_zone; + printk(KERN_DEBUG + "ISOFS: changing to secondary root\n"); + iput(inode); + inode = iget(s, s->u.isofs_sb.s_firstdatazone); + } } if (opt.check == 'u') { @@ -766,32 +786,46 @@ if (joliet_level) opt.check = 'r'; else opt.check = 's'; } + s->u.isofs_sb.s_joliet_level = joliet_level; + /* check the root inode */ + if (!inode) + goto out_no_root; + if (!inode->i_op) + goto out_bad_root; + /* get the root dentry */ s->s_root = d_alloc_root(inode, NULL); if (!(s->s_root)) goto out_no_root; + table = 0; if (joliet_level) table += 2; if (opt.check == 'r') table++; s->s_root->d_op = &isofs_dentry_ops[table]; - if(!check_disk_change(dev)) { - brelse(bh); - unlock_super(s); - return s; - } - /* - * Disk changed? Free the root dentry and clean up ... - */ - dput(s->s_root); - goto out_freechar; + unlock_super(s); + return s; /* - * Display error message + * Display error messages and free resources. */ -out_no_root: - printk(KERN_ERR "isofs_read_super: get root inode failed\n"); +out_bad_root: + printk(KERN_WARNING "isofs_read_super: root inode not initialized\n"); goto out_iput; +out_no_root: + printk(KERN_WARNING "isofs_read_super: get root inode failed\n"); +out_iput: + iput(inode); +#ifdef CONFIG_JOLIET + if (s->u.isofs_sb.s_nls_iocharset) + unload_nls(s->u.isofs_sb.s_nls_iocharset); +#endif + goto out_unlock; +out_no_read: + printk(KERN_WARNING "isofs_read_super: " + "bread failed, dev=%s, iso_blknum=%d, block=%d\n", + kdevname(dev), iso_blknum, block); + goto out_unlock; out_bad_zone_size: printk(KERN_WARNING "Bad logical zone size %ld\n", s->u.isofs_sb.s_log_zone_size); @@ -808,23 +842,7 @@ out_unknown_format: if (!silent) printk(KERN_WARNING "Unable to identify CD-ROM format.\n"); - goto out_freebh; -out_no_read: - printk(KERN_WARNING "isofs_read_super: " - "bread failed, dev=%s, iso_blknum=%d, block=%d\n", - kdevname(dev), iso_blknum, block); - goto out_unlock; - /* - * Cascaded error cleanup to ensure all resources are freed. - */ -out_iput: - iput(inode); -out_freechar: -#ifdef CONFIG_JOLIET - if (s->u.isofs_sb.s_nls_iocharset) - unload_nls(s->u.isofs_sb.s_nls_iocharset); -#endif out_freebh: brelse(bh); out_unlock: @@ -945,101 +963,113 @@ static int isofs_read_level3_size(struct inode * inode) { + unsigned long ino = inode->i_ino; unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); + int high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra; struct buffer_head * bh = NULL; - struct iso_directory_record * raw_inode = NULL; /* quiet gcc */ - unsigned char *pnt = NULL; - void *cpnt = NULL; - int block = 0; /* Quiet GCC */ - unsigned long ino; - int i; + int block = 0; + int i = 0; + void *cpnt; + struct iso_directory_record * raw_inode; inode->i_size = 0; inode->u.isofs_i.i_next_section_ino = 0; - ino = inode->i_ino; - i = 0; do { - if(i > 100) { - printk("isofs_read_level3_size: More than 100 file sections ?!?, aborting...\n" - "isofs_read_level3_size: inode=%lu ino=%lu\n", inode->i_ino, ino); - return 0; + unsigned char *pnt; + unsigned int reclen; + int offset = (ino & (bufsize - 1)); + + cpnt = NULL; + /* Check whether to update our buffer */ + if (block != ino >> ISOFS_BUFFER_BITS(inode)) { + block = ino >> ISOFS_BUFFER_BITS(inode); + brelse(bh); + bh = bread(inode->i_dev, block, bufsize); + if (!bh) + goto out_noread; } + pnt = ((unsigned char *) bh->b_data + offset); + raw_inode = ((struct iso_directory_record *) pnt); + /* + * Note: this is invariant even if the record + * spans buffers and must be copied ... + */ + reclen = *pnt; - if(bh == NULL || block != ino >> ISOFS_BUFFER_BITS(inode)) { - if(bh) brelse(bh); - block = ino >> ISOFS_BUFFER_BITS(inode); - if (!(bh=bread(inode->i_dev,block, bufsize))) { - printk("unable to read i-node block"); - return 1; - } + /* N.B. this test doesn't trigger the i++ code ... */ + if(reclen == 0) { + ino = (ino & ~(ISOFS_BLOCK_SIZE - 1)) + ISOFS_BLOCK_SIZE; + continue; } - pnt = ((unsigned char *) bh->b_data - + (ino & (bufsize - 1))); - - if ((ino & (bufsize - 1)) + *pnt > bufsize){ - int frag1, offset; + + /* Check whether the raw inode spans the buffer ... */ + if (offset + reclen > bufsize){ + int frag1 = bufsize - offset; - offset = (ino & (bufsize - 1)); - frag1 = bufsize - offset; - cpnt = kmalloc(*pnt,GFP_KERNEL); - if (cpnt == NULL) { - printk(KERN_INFO "NoMem ISO inode %lu\n",inode->i_ino); - brelse(bh); - return 1; - } - memcpy(cpnt, bh->b_data + offset, frag1); + cpnt = kmalloc(reclen, GFP_KERNEL); + if (cpnt == NULL) + goto out_nomem; + memcpy(cpnt, pnt, frag1); brelse(bh); - if (!(bh = bread(inode->i_dev,++block, bufsize))) { - kfree(cpnt); - printk("unable to read i-node block"); - return 1; - } - offset += *pnt - bufsize; + bh = bread(inode->i_dev, ++block, bufsize); + if (!bh) + goto out_noread; + offset += reclen - bufsize; memcpy((char *)cpnt+frag1, bh->b_data, offset); - pnt = ((unsigned char *) cpnt); + raw_inode = ((struct iso_directory_record *) cpnt); } - - if(*pnt == 0) { - ino = (ino & ~(ISOFS_BLOCK_SIZE - 1)) + ISOFS_BLOCK_SIZE; - continue; - } - raw_inode = ((struct iso_directory_record *) pnt); inode->i_size += isonum_733 (raw_inode->size); if(i == 1) inode->u.isofs_i.i_next_section_ino = ino; - ino += *pnt; - if (cpnt) { + ino += reclen; + if (cpnt) kfree (cpnt); - cpnt = NULL; - } i++; - } while(raw_inode->flags[-inode->i_sb->u.isofs_sb.s_high_sierra] & 0x80); + if(i > 100) + goto out_toomany; + } while(raw_inode->flags[-high_sierra] & 0x80); +out: brelse(bh); return 0; + +out_nomem: + printk(KERN_INFO "ISOFS: NoMem ISO inode %lu\n", inode->i_ino); + brelse(bh); + return 1; +out_noread: + printk(KERN_INFO "ISOFS: unable to read i-node block %d\n", block); + if (cpnt) + kfree(cpnt); + return 1; +out_toomany: + printk(KERN_INFO "isofs_read_level3_size: " + "More than 100 file sections ?!?, aborting...\n" + "isofs_read_level3_size: inode=%lu ino=%lu\n", + inode->i_ino, ino); + goto out; } void isofs_read_inode(struct inode * inode) { + struct super_block *sb = inode->i_sb; unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); + int block = inode->i_ino >> ISOFS_BUFFER_BITS(inode); + int high_sierra = sb->u.isofs_sb.s_high_sierra; struct buffer_head * bh; struct iso_directory_record * raw_inode; - unsigned char *pnt = NULL; - int high_sierra; - int block; - int volume_seq_no ; - int i; + unsigned char *pnt; + int volume_seq_no, i; - block = inode->i_ino >> ISOFS_BUFFER_BITS(inode); - if (!(bh=bread(inode->i_dev,block, bufsize))) { - printk("unable to read i-node block"); - goto fail; + bh = bread(inode->i_dev, block, bufsize); + if (!bh) { + printk(KERN_WARNING "ISOFS: unable to read i-node block\n"); + goto fail; } pnt = ((unsigned char *) bh->b_data + (inode->i_ino & (bufsize - 1))); raw_inode = ((struct iso_directory_record *) pnt); - high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra; if (raw_inode->flags[-high_sierra] & 2) { inode->i_mode = S_IRUGO | S_IXUGO | S_IFDIR; @@ -1049,10 +1079,13 @@ easier to give 1 which tells find to do it the hard way. */ } else { - inode->i_mode = inode->i_sb->u.isofs_sb.s_mode; /* Everybody gets to read the file. */ + /* Everybody gets to read the file. */ + inode->i_mode = inode->i_sb->u.isofs_sb.s_mode; inode->i_nlink = 1; inode->i_mode |= S_IFREG; -/* If there are no periods in the name, then set the execute permission bit */ + /* If there are no periods in the name, + * then set the execute permission bit + */ for(i=0; i< raw_inode->name_len[0]; i++) if(raw_inode->name[i]=='.' || raw_inode->name[i]==';') break; @@ -1133,14 +1166,16 @@ #ifdef DEBUG printk("Inode: %x extent: %x\n",inode->i_ino, inode->u.isofs_i.i_first_extent); #endif - brelse(bh); - - inode->i_op = NULL; /* get the volume sequence number */ volume_seq_no = isonum_723 (raw_inode->volume_sequence_number) ; /* + * All done with buffer ... no more references to buffer memory! + */ + brelse(bh); + + /* * Disable checking if we see any volume number other than 0 or 1. * We could use the cruft option, but that has multiple purposes, one * of which is limiting the file size to 16Mb. Thus we silently allow @@ -1152,6 +1187,8 @@ inode->i_sb->u.isofs_sb.s_cruft = 'y'; } + /* Install the inode operations vector */ + inode->i_op = NULL; #ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS if (inode->i_sb->u.isofs_sb.s_cruft != 'y' && (volume_seq_no != 0) && (volume_seq_no != 1)) { @@ -1173,6 +1210,7 @@ init_fifo(inode); } return; + fail: /* With a data error we return this information */ inode->i_mtime = inode->i_atime = inode->i_ctime = 0; diff -u --recursive --new-file v2.1.122/linux/fs/isofs/rock.c linux/fs/isofs/rock.c --- v2.1.122/linux/fs/isofs/rock.c Wed Jun 24 22:54:09 1998 +++ linux/fs/isofs/rock.c Fri Sep 25 16:27:13 1998 @@ -54,25 +54,23 @@ {if (buffer) kfree(buffer); \ if (cont_extent){ \ int block, offset, offset1; \ - struct buffer_head * bh; \ + struct buffer_head * pbh; \ buffer = kmalloc(cont_size,GFP_KERNEL); \ if (!buffer) goto out; \ block = cont_extent; \ offset = cont_offset; \ offset1 = 0; \ - if(buffer) { \ - bh = bread(DEV->i_dev, block, ISOFS_BUFFER_SIZE(DEV)); \ - if(bh){ \ - memcpy(buffer + offset1, bh->b_data + offset, cont_size - offset1); \ - brelse(bh); \ - chr = (unsigned char *) buffer; \ - len = cont_size; \ - cont_extent = 0; \ - cont_size = 0; \ - cont_offset = 0; \ - goto LABEL; \ - }; \ - } \ + pbh = bread(DEV->i_dev, block, ISOFS_BUFFER_SIZE(DEV)); \ + if(pbh){ \ + memcpy(buffer + offset1, pbh->b_data + offset, cont_size - offset1); \ + brelse(pbh); \ + chr = (unsigned char *) buffer; \ + len = cont_size; \ + cont_extent = 0; \ + cont_size = 0; \ + cont_offset = 0; \ + goto LABEL; \ + }; \ printk("Unable to read rock-ridge attributes\n"); \ }} @@ -162,7 +160,6 @@ if (!inode->i_sb->u.isofs_sb.s_rock) return 0; *retname = 0; - retnamlen = 0; SETUP_ROCK_RIDGE(de, chr, len); repeat: @@ -364,6 +361,8 @@ inode->u.isofs_i.i_first_extent = isonum_733(rr->u.CL.location) << inode -> i_sb -> u.isofs_sb.s_log_zone_size; reloc = iget(inode->i_sb, inode->u.isofs_i.i_first_extent); + if (!reloc) + goto out; inode->i_mode = reloc->i_mode; inode->i_nlink = reloc->i_nlink; inode->i_uid = reloc->i_uid; @@ -396,8 +395,8 @@ unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); unsigned char bufbits = ISOFS_BUFFER_BITS(inode); struct buffer_head * bh; + char * rpnt = NULL; unsigned char * pnt; - char * rpnt; struct iso_directory_record * raw_inode; CONTINUE_DECLS; int block; @@ -410,13 +409,10 @@ if (!inode->i_sb->u.isofs_sb.s_rock) panic("Cannot have symlink with high sierra variant of iso filesystem\n"); - rpnt = 0; - block = inode->i_ino >> bufbits; - if (!(bh=bread(inode->i_dev,block, bufsize))) { - printk("unable to read i-node block"); - return NULL; - }; + bh = bread(inode->i_dev, block, bufsize); + if (!bh) + goto out_noread; pnt = ((unsigned char *) bh->b_data) + (inode->i_ino & (bufsize - 1)); @@ -425,10 +421,8 @@ /* * If we go past the end of the buffer, there is some sort of error. */ - if ((inode->i_ino & (bufsize - 1)) + *pnt > bufsize){ - printk("symlink spans iso9660 blocks\n"); - return NULL; - }; + if ((inode->i_ino & (bufsize - 1)) + *pnt > bufsize) + goto out_bad_span; /* Now test for possible Rock Ridge extensions which will override some of these numbers in the inode structure. */ @@ -511,16 +505,23 @@ }; }; MAYBE_CONTINUE(repeat,inode); - brelse(bh); - return rpnt; - out: - if(buffer) kfree(buffer); - return 0; +out_freebh: + brelse(bh); + return rpnt; + + /* error exit from macro */ +out: + if(buffer) + kfree(buffer); + if(rpnt) + kfree(rpnt); + rpnt = NULL; + goto out_freebh; +out_noread: + printk("unable to read i-node block"); + goto out_freebh; +out_bad_span: + printk("symlink spans iso9660 blocks\n"); + goto out_freebh; } - - - - - - diff -u --recursive --new-file v2.1.122/linux/fs/isofs/symlink.c linux/fs/isofs/symlink.c --- v2.1.122/linux/fs/isofs/symlink.c Wed Jun 24 22:54:09 1998 +++ linux/fs/isofs/symlink.c Sat Sep 19 13:42:23 1998 @@ -19,7 +19,7 @@ #include static int isofs_readlink(struct dentry *, char *, int); -static struct dentry * isofs_follow_link(struct dentry *, struct dentry *); +static struct dentry * isofs_follow_link(struct dentry *, struct dentry *, unsigned int); /* * symlinks can't do much... @@ -66,7 +66,8 @@ } static struct dentry * isofs_follow_link(struct dentry * dentry, - struct dentry *base) + struct dentry *base, + unsigned int follow) { char * pnt; @@ -76,7 +77,7 @@ return ERR_PTR(-ELOOP); } - base = lookup_dentry(pnt, base, 1); + base = lookup_dentry(pnt, base, follow); kfree(pnt); return base; diff -u --recursive --new-file v2.1.122/linux/fs/minix/namei.c linux/fs/minix/namei.c --- v2.1.122/linux/fs/minix/namei.c Tue Jun 23 10:01:25 1998 +++ linux/fs/minix/namei.c Sat Sep 19 15:23:42 1998 @@ -88,7 +88,7 @@ { unsigned long hash; int i; - const char *name; + const unsigned char *name; i = dentry->d_inode->i_sb->u.minix_sb.s_namelen; if (i >= qstr->len) diff -u --recursive --new-file v2.1.122/linux/fs/minix/symlink.c linux/fs/minix/symlink.c --- v2.1.122/linux/fs/minix/symlink.c Sun Jan 4 00:53:41 1998 +++ linux/fs/minix/symlink.c Sat Sep 19 13:42:44 1998 @@ -15,7 +15,7 @@ #include static int minix_readlink(struct dentry *, char *, int); -static struct dentry *minix_follow_link(struct dentry *, struct dentry *); +static struct dentry *minix_follow_link(struct dentry *, struct dentry *, unsigned int); /* * symlinks can't do much... @@ -41,7 +41,8 @@ }; static struct dentry * minix_follow_link(struct dentry * dentry, - struct dentry * base) + struct dentry * base, + unsigned int follow) { struct inode *inode = dentry->d_inode; struct buffer_head * bh; @@ -52,7 +53,7 @@ return ERR_PTR(-EIO); } UPDATE_ATIME(inode); - base = lookup_dentry(bh->b_data, base, 1); + base = lookup_dentry(bh->b_data, base, follow); brelse(bh); return base; } diff -u --recursive --new-file v2.1.122/linux/fs/msdos/namei.c linux/fs/msdos/namei.c --- v2.1.122/linux/fs/msdos/namei.c Thu Sep 17 17:53:38 1998 +++ linux/fs/msdos/namei.c Thu Sep 17 09:43:46 1998 @@ -266,6 +266,7 @@ res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &bh, &de, &ino); + if (res == -ENOENT) goto add; if (res < 0) @@ -275,7 +276,7 @@ /* try to get the inode */ res = -EACCES; - inode = iget(dir->i_sb, ino); + inode = iget(sb, ino); if (!inode) goto out; if (!inode->i_sb || @@ -289,9 +290,9 @@ iput(inode); goto out; } - res = 0; add: d_add(dentry, inode); + res = 0; out: return res; } @@ -446,14 +447,14 @@ if (dir->i_dev != inode->i_dev || dir == inode) printk("msdos_rmdir: impossible condition\n"); /* - * Prune any child dentries, then verify that - * the directory is empty and not in use. + * Check whether the directory is empty, then prune + * any child dentries and make sure it's not in use. */ - shrink_dcache_parent(dentry); res = msdos_empty(inode); if (res) goto rmdir_done; res = -EBUSY; + shrink_dcache_parent(dentry); if (dentry->d_count > 1) { #ifdef MSDOS_DEBUG printk("msdos_rmdir: %s/%s busy, d_count=%d\n", @@ -476,6 +477,7 @@ de->name[0] = DELETED_FLAG; fat_mark_buffer_dirty(sb, bh, 1); res = 0; + rmdir_done: fat_brelse(sb, bh); return res; @@ -499,18 +501,21 @@ return res; is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.'); fat_lock_creation(); - if (fat_scan(dir,msdos_name,&bh,&de,&ino,SCAN_ANY) >= 0) { - fat_unlock_creation(); - /* N.B. does this need to be released on the other path? */ - fat_brelse(sb, bh); - return -EEXIST; - } + if (fat_scan(dir,msdos_name,&bh,&de,&ino,SCAN_ANY) >= 0) + goto out_exist; + res = msdos_create_entry(dir,msdos_name,1,is_hid, &inode); if (res < 0) goto out_unlock; + dir->i_nlink++; inode->i_nlink = 2; /* no need to mark them dirty */ MSDOS_I(inode)->i_busy = 1; /* prevent lookups */ + /* + * Instantiate the dentry now, in case we need to cleanup. + */ + d_instantiate(dentry, inode); + if ((res = fat_add_cluster(inode)) < 0) goto mkdir_error; if ((res = msdos_create_entry(inode,MSDOS_DOT,1,0,&dot)) < 0) @@ -521,9 +526,9 @@ dot->i_nlink = inode->i_nlink; mark_inode_dirty(dot); iput(dot); + if ((res = msdos_create_entry(inode,MSDOS_DOTDOT,1,0,&dot)) < 0) goto mkdir_error; - fat_unlock_creation(); dot->i_size = dir->i_size; MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start; MSDOS_I(dot)->i_logstart = MSDOS_I(dir)->i_logstart; @@ -531,15 +536,22 @@ mark_inode_dirty(dot); MSDOS_I(inode)->i_busy = 0; iput(dot); - d_instantiate(dentry, inode); - return 0; + res = 0; -mkdir_error: - if (msdos_rmdir(dir,dentry) < 0) - fat_fs_panic(dir->i_sb,"rmdir in mkdir failed"); out_unlock: fat_unlock_creation(); return res; + +mkdir_error: + printk("msdos_mkdir: error=%d, attempting cleanup\n", res); + if (msdos_rmdir(dir,dentry) < 0) + fat_fs_panic(dir->i_sb,"rmdir in mkdir failed"); + goto out_unlock; + +out_exist: + fat_brelse(sb, bh); + res = -EEXIST; + goto out_unlock; } /***** Unlink a file */ @@ -636,10 +648,14 @@ if ((old_de->attr & ATTR_SYS)) goto out_error; + if (S_ISDIR(new_inode->i_mode)) { + /* make sure it's empty */ + error = msdos_empty(new_inode); + if (error) + goto out_error; #ifdef MSDOS_CHECK_BUSY - /* check for a busy dentry */ - error = -EBUSY; - if (new_dentry->d_count > 1) { + /* check for a busy dentry */ + error = -EBUSY; shrink_dcache_parent(new_dentry); if (new_dentry->d_count > 1) { printk("msdos_rename_same: %s/%s busy, count=%d\n", @@ -647,20 +663,19 @@ new_dentry->d_count); goto out_error; } - } #endif - - if (S_ISDIR(new_inode->i_mode)) { new_dir->i_nlink--; mark_inode_dirty(new_dir); } new_inode->i_nlink = 0; MSDOS_I(new_inode)->i_busy = 1; mark_inode_dirty(new_inode); -#ifdef MSDOS_CHECK_BUSY - /* d_delete the dentry, as we killed its inode */ - d_delete(new_dentry); -#endif + /* + * Make it negative if it's not busy; + * otherwise let d_move() drop it. + */ + if (new_dentry->d_count == 1) + d_delete(new_dentry); new_de->name[0] = DELETED_FLAG; fat_mark_buffer_dirty(sb, new_bh, 1); @@ -763,16 +778,22 @@ } #endif if (S_ISDIR(new_inode->i_mode)) { + /* make sure it's empty */ + error = msdos_empty(new_inode); + if (error) + goto out_new; new_dir->i_nlink--; mark_inode_dirty(new_dir); } new_inode->i_nlink = 0; MSDOS_I(new_inode)->i_busy = 1; mark_inode_dirty(new_inode); -#ifdef MSDOS_CHECK_BUSY - /* d_delete the dentry, as we killed its inode */ - d_delete(new_dentry); -#endif + /* + * Make it negative if it's not busy; + * otherwise let d_move() drop it. + */ + if (new_dentry->d_count == 1) + d_delete(new_dentry); new_de->name[0] = DELETED_FLAG; fat_mark_buffer_dirty(sb, new_bh, 1); fat_brelse(sb, new_bh); @@ -804,12 +825,20 @@ free_inode = iget(sb, free_ino); if (!free_inode) goto out_iput; + /* make sure it's not busy! */ + if (MSDOS_I(free_inode)->i_busy) + printk(KERN_ERR "msdos_rename_diff: new inode %ld busy!\n", + (ino_t) free_ino); + if (!list_empty(&free_inode->i_dentry)) + printk("msdos_rename_diff: free inode has aliases??\n"); msdos_read_inode(free_inode); + fat_mark_buffer_dirty(sb, free_bh, 1); /* * Make sure the old dentry isn't busy, * as we need to change inodes ... */ + error = -EBUSY; if (old_dentry->d_count > 1) { shrink_dcache_parent(old_dentry); if (old_dentry->d_count > 1) { @@ -836,6 +865,11 @@ MSDOS_I(free_inode)->i_logstart = MSDOS_I(old_inode)->i_logstart; MSDOS_I(free_inode)->i_attrs = MSDOS_I(old_inode)->i_attrs; + /* release the old inode's resources */ + MSDOS_I(old_inode)->i_start = 0; + MSDOS_I(old_inode)->i_logstart = 0; + old_inode->i_nlink = 0; + /* * Install the new inode ... */ @@ -845,7 +879,6 @@ mark_inode_dirty(old_inode); old_de->name[0] = DELETED_FLAG; fat_mark_buffer_dirty(sb, old_bh, 1); - fat_mark_buffer_dirty(sb, free_bh, 1); iput(old_inode); /* a directory? */ @@ -854,13 +887,13 @@ MSDOS_I(dotdot_inode)->i_logstart = MSDOS_I(new_dir)->i_logstart; dotdot_de->start = CT_LE_W(MSDOS_I(new_dir)->i_logstart); dotdot_de->starthi = CT_LE_W((MSDOS_I(new_dir)->i_logstart) >> 16); - mark_inode_dirty(dotdot_inode); - fat_mark_buffer_dirty(sb, dotdot_bh, 1); old_dir->i_nlink--; new_dir->i_nlink++; /* no need to mark them dirty */ dotdot_inode->i_nlink = new_dir->i_nlink; + mark_inode_dirty(dotdot_inode); iput(dotdot_inode); + fat_mark_buffer_dirty(sb, dotdot_bh, 1); fat_brelse(sb, dotdot_bh); } diff -u --recursive --new-file v2.1.122/linux/fs/namei.c linux/fs/namei.c --- v2.1.122/linux/fs/namei.c Thu Sep 17 17:53:38 1998 +++ linux/fs/namei.c Tue Sep 22 17:47:27 1998 @@ -280,7 +280,19 @@ return result; } -static struct dentry * do_follow_link(struct dentry *base, struct dentry *dentry) +/* + * The bitmask for a lookup event: + * - follow links at the end + * - require a directory + * - ending slashes ok even for nonexistent files + * - internal "there are more path compnents" flag + */ +#define LOOKUP_FOLLOW (1) +#define LOOKUP_DIRECTORY (2) +#define LOOKUP_SLASHOK (4) +#define LOOKUP_CONTINUE (8) + +static struct dentry * do_follow_link(struct dentry *base, struct dentry *dentry, unsigned int follow) { struct inode * inode = dentry->d_inode; @@ -290,7 +302,7 @@ current->link_count++; /* This eats the base */ - result = inode->i_op->follow_link(dentry, base); + result = inode->i_op->follow_link(dentry, base, follow); current->link_count--; dput(dentry); return result; @@ -320,9 +332,10 @@ * This is the basic name resolution function, turning a pathname * into the final dentry. */ -struct dentry * lookup_dentry(const char * name, struct dentry * base, int follow_link) +struct dentry * lookup_dentry(const char * name, struct dentry * base, unsigned int lookup_flags) { struct dentry * dentry; + struct inode *inode; if (*name == '/') { if (base) @@ -338,22 +351,16 @@ if (!*name) goto return_base; + inode = base->d_inode; + lookup_flags &= LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_SLASHOK; + /* At this point we know we have a real path component. */ for(;;) { int err; unsigned long hash; struct qstr this; - struct inode *inode; - char c, follow; - - dentry = ERR_PTR(-ENOENT); - inode = base->d_inode; - if (!inode) - break; - - dentry = ERR_PTR(-ENOTDIR); - if (!inode->i_op || !inode->i_op->lookup) - break; + unsigned int flags; + unsigned int c; err = permission(inode, MAY_EXEC); dentry = ERR_PTR(err); @@ -361,23 +368,28 @@ break; this.name = name; - c = *name; + c = *(const unsigned char *)name; hash = init_name_hash(); do { + name++; hash = partial_name_hash(c, hash); - c = *++name; + c = *(const unsigned char *)name; } while (c && (c != '/')); this.len = name - (const char *) this.name; this.hash = end_name_hash(hash); /* remove trailing slashes? */ - follow = follow_link; + flags = lookup_flags; if (c) { - follow |= c; + char tmp; + + flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY; do { - c = *++name; - } while (c == '/'); + tmp = *++name; + } while (tmp == '/'); + if (tmp) + flags |= LOOKUP_CONTINUE; } /* @@ -407,15 +419,47 @@ /* Check mountpoints.. */ dentry = follow_mount(dentry); - if (!follow) + if (!(flags & LOOKUP_FOLLOW)) break; - base = do_follow_link(base, dentry); - if (c && !IS_ERR(base)) - continue; + base = do_follow_link(base, dentry, flags); + if (IS_ERR(base)) + goto return_base; + inode = base->d_inode; + if (flags & LOOKUP_DIRECTORY) { + if (!inode) + goto no_inode; + dentry = ERR_PTR(-ENOTDIR); + if (!inode->i_op || !inode->i_op->lookup) + break; + if (flags & LOOKUP_CONTINUE) + continue; + } return_base: return base; +/* + * The case of a nonexisting file is special. + * + * In the middle of a pathname lookup (ie when + * LOOKUP_CONTINUE is set), it's an obvious + * error and returns ENOENT. + * + * At the end of a pathname lookup it's legal, + * and we return a negative dentry. However, we + * get here only if there were trailing slashes, + * which is legal only if we know it's supposed + * to be a directory (ie "mkdir"). Thus the + * LOOKUP_SLASHOK flag. + */ +no_inode: + dentry = ERR_PTR(-ENOENT); + if (flags & LOOKUP_CONTINUE) + break; + if (flags & LOOKUP_SLASHOK) + goto return_base; + dentry = ERR_PTR(-ENOTDIR); + break; } dput(base); return dentry; @@ -431,7 +475,7 @@ * namei exists in two versions: namei/lnamei. The only difference is * that namei follows links, while lnamei does not. */ -struct dentry * __namei(const char *pathname, int follow_link) +struct dentry * __namei(const char *pathname, unsigned int lookup_flags) { char *name; struct dentry *dentry; @@ -439,7 +483,7 @@ name = getname(pathname); dentry = (struct dentry *) name; if (!IS_ERR(name)) { - dentry = lookup_dentry(name, NULL, follow_link); + dentry = lookup_dentry(name, NULL, lookup_flags); putname(name); if (!IS_ERR(dentry)) { if (!dentry->d_inode) { @@ -637,7 +681,7 @@ struct dentry *dentry, *retval; mode &= ~current->fs->umask; - dentry = lookup_dentry(filename, NULL, 1); + dentry = lookup_dentry(filename, NULL, LOOKUP_FOLLOW); if (IS_ERR(dentry)) return dentry; @@ -721,7 +765,7 @@ struct dentry *dir; struct dentry *dentry; - dentry = lookup_dentry(pathname, NULL, 0); + dentry = lookup_dentry(pathname, NULL, LOOKUP_SLASHOK); error = PTR_ERR(dentry); if (IS_ERR(dentry)) goto exit; @@ -1128,7 +1172,16 @@ if (IS_ERR(old_dentry)) goto exit; - new_dentry = lookup_dentry(newname, NULL, 0); + error = -ENOENT; + if (!old_dentry->d_inode) + goto exit; + + { + unsigned int flags = 0; + if (S_ISDIR(old_dentry->d_inode->i_mode)) + flags = LOOKUP_SLASHOK; + new_dentry = lookup_dentry(newname, NULL, flags); + } error = PTR_ERR(new_dentry); if (IS_ERR(new_dentry)) @@ -1138,10 +1191,6 @@ old_dir = get_parent(old_dentry); double_lock(new_dir, old_dir); - - error = -ENOENT; - if (!old_dentry->d_inode) - goto exit_lock; error = permission(old_dir->d_inode,MAY_WRITE | MAY_EXEC); if (error) diff -u --recursive --new-file v2.1.122/linux/fs/nfs/dir.c linux/fs/nfs/dir.c --- v2.1.122/linux/fs/nfs/dir.c Wed Sep 9 14:51:09 1998 +++ linux/fs/nfs/dir.c Sat Sep 26 11:11:17 1998 @@ -416,23 +416,16 @@ */ error = nfs_proc_lookup(NFS_DSERVER(parent), NFS_FH(parent), dentry->d_name.name, &fhandle, &fattr); - if (error) { -printk("nfs_lookup_revalidate: error=%d\n", error); + if (error) goto out_bad; - } /* Inode number matches? */ - if (fattr.fileid != inode->i_ino) { -printk("nfs_lookup_revalidate: %s/%s inode mismatch, old=%ld, new=%u\n", -parent->d_name.name, dentry->d_name.name, inode->i_ino, fattr.fileid); + if (fattr.fileid != inode->i_ino) goto out_bad; - } + /* Filehandle matches? */ - if (memcmp(dentry->d_fsdata, &fhandle, sizeof(struct nfs_fh))) { -printk("nfs_lookup_revalidate: %s/%s fh changed\n", -parent->d_name.name, dentry->d_name.name); + if (memcmp(dentry->d_fsdata, &fhandle, sizeof(struct nfs_fh))) goto out_bad; - } out_valid: return 1; diff -u --recursive --new-file v2.1.122/linux/fs/nfs/inode.c linux/fs/nfs/inode.c --- v2.1.122/linux/fs/nfs/inode.c Wed Aug 26 11:37:43 1998 +++ linux/fs/nfs/inode.c Fri Sep 25 16:26:30 1998 @@ -322,18 +322,20 @@ goto out_shutdown; out_no_iod: - printk("NFS: couldn't start rpciod!\n"); + printk(KERN_WARNING "NFS: couldn't start rpciod!\n"); out_shutdown: rpc_shutdown_client(server->client); - goto out_unlock; + goto out_free_host; out_no_client: - printk("NFS: cannot create RPC client.\n"); + printk(KERN_WARNING "NFS: cannot create RPC client.\n"); xprt_destroy(xprt); - goto out_unlock; + goto out_free_host; out_no_xprt: - printk("NFS: cannot create RPC transport.\n"); + printk(KERN_WARNING "NFS: cannot create RPC transport.\n"); + +out_free_host: kfree(server->hostname); out_unlock: unlock_super(sb); @@ -393,9 +395,10 @@ tmp = head; while ((tmp = tmp->next) != head) { struct dentry *dentry = list_entry(tmp, struct dentry, d_alias); +printk("nfs_free_dentries: found %s/%s, d_count=%d, hashed=%d\n", +dentry->d_parent->d_name.name, dentry->d_name.name, +dentry->d_count, !list_empty(&dentry->d_hash)); if (!dentry->d_count) { -printk("nfs_free_dentries: freeing %s/%s, i_count=%d\n", -dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_count); dget(dentry); d_drop(dentry); dput(dentry); diff -u --recursive --new-file v2.1.122/linux/fs/nfs/symlink.c linux/fs/nfs/symlink.c --- v2.1.122/linux/fs/nfs/symlink.c Sun Jan 4 00:53:41 1998 +++ linux/fs/nfs/symlink.c Sat Sep 19 13:43:09 1998 @@ -19,7 +19,7 @@ #include static int nfs_readlink(struct dentry *, char *, int); -static struct dentry *nfs_follow_link(struct dentry *, struct dentry *); +static struct dentry *nfs_follow_link(struct dentry *, struct dentry *, unsigned int); /* * symlinks can't do much... @@ -68,7 +68,7 @@ } static struct dentry * -nfs_follow_link(struct dentry * dentry, struct dentry *base) +nfs_follow_link(struct dentry * dentry, struct dentry *base, unsigned int follow) { int error; unsigned int len; @@ -94,7 +94,7 @@ path[len] = 0; kfree(mem); - result = lookup_dentry(path, base, 1); + result = lookup_dentry(path, base, follow); kfree(path); out: return result; diff -u --recursive --new-file v2.1.122/linux/fs/pipe.c linux/fs/pipe.c --- v2.1.122/linux/fs/pipe.c Wed Aug 26 11:37:43 1998 +++ linux/fs/pipe.c Sat Sep 19 15:13:19 1998 @@ -92,7 +92,7 @@ size_t count, loff_t *ppos) { struct inode * inode = filp->f_dentry->d_inode; - ssize_t chars = 0, free = 0, written = 0; + ssize_t chars = 0, free = 0, written = 0, err=0; char *pipebuf; if (ppos != &filp->f_pos) @@ -107,16 +107,26 @@ free = count; else free = 1; /* can't do it atomically, wait for any free space */ + up(&inode->i_sem); + if (down_interruptible(&inode->i_atomic_write)) { + down(&inode->i_sem); + return -ERESTARTSYS; + } while (count>0) { while ((PIPE_FREE(*inode) < free) || PIPE_LOCK(*inode)) { if (!PIPE_READERS(*inode)) { /* no readers */ send_sig(SIGPIPE,current,0); - return written? :-EPIPE; + err = -EPIPE; + goto errout; + } + if (signal_pending(current)) { + err = -ERESTARTSYS; + goto errout; + } + if (filp->f_flags & O_NONBLOCK) { + err = -EAGAIN; + goto errout; } - if (signal_pending(current)) - return written? :-ERESTARTSYS; - if (filp->f_flags & O_NONBLOCK) - return written? :-EAGAIN; interruptible_sleep_on(&PIPE_WAIT(*inode)); } PIPE_LOCK(*inode)++; @@ -139,7 +149,10 @@ } inode->i_ctime = inode->i_mtime = CURRENT_TIME; mark_inode_dirty(inode); - return written; +errout: + up(&inode->i_atomic_write); + down(&inode->i_sem); + return written ? written : err; } static long long pipe_lseek(struct file * file, long long offset, int orig) diff -u --recursive --new-file v2.1.122/linux/fs/proc/link.c linux/fs/proc/link.c --- v2.1.122/linux/fs/proc/link.c Wed Aug 26 11:37:43 1998 +++ linux/fs/proc/link.c Sat Sep 19 15:11:37 1998 @@ -17,7 +17,7 @@ #include static int proc_readlink(struct dentry *, char *, int); -static struct dentry * proc_follow_link(struct dentry *, struct dentry *); +static struct dentry * proc_follow_link(struct dentry *, struct dentry *, unsigned int); /* * links can't do much... @@ -57,7 +57,8 @@ }; static struct dentry * proc_follow_link(struct dentry *dentry, - struct dentry *base) + struct dentry *base, + unsigned int follow) { struct inode *inode = dentry->d_inode; struct task_struct *p; @@ -172,7 +173,7 @@ { int error; - dentry = proc_follow_link(dentry, NULL); + dentry = proc_follow_link(dentry, NULL, 1); error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { error = -ENOENT; diff -u --recursive --new-file v2.1.122/linux/fs/proc/mem.c linux/fs/proc/mem.c --- v2.1.122/linux/fs/proc/mem.c Wed Aug 26 11:37:43 1998 +++ linux/fs/proc/mem.c Wed Sep 23 15:24:37 1998 @@ -215,7 +215,7 @@ pgd_t *src_dir, *dest_dir; pmd_t *src_middle, *dest_middle; pte_t *src_table, *dest_table; - unsigned long stmp, dtmp; + unsigned long stmp, dtmp, mapnr; struct vm_area_struct *src_vma = NULL; struct inode *inode = file->f_dentry->d_inode; @@ -296,7 +296,9 @@ set_pte(src_table, pte_mkdirty(*src_table)); set_pte(dest_table, *src_table); - atomic_inc(&mem_map[MAP_NR(pte_page(*src_table))].count); + mapnr = MAP_NR(pte_page(*src_table)); + if (mapnr < max_mapnr) + atomic_inc(&mem_map[MAP_NR(pte_page(*src_table))].count); stmp += PAGE_SIZE; dtmp += PAGE_SIZE; diff -u --recursive --new-file v2.1.122/linux/fs/proc/proc_devtree.c linux/fs/proc/proc_devtree.c --- v2.1.122/linux/fs/proc/proc_devtree.c Thu Apr 23 20:21:37 1998 +++ linux/fs/proc/proc_devtree.c Sat Sep 19 13:43:36 1998 @@ -42,7 +42,7 @@ */ static int devtree_readlink(struct dentry *, char *, int); -static struct dentry *devtree_follow_link(struct dentry *, struct dentry *); +static struct dentry *devtree_follow_link(struct dentry *, struct dentry *, unsigned int); struct inode_operations devtree_symlink_inode_operations = { NULL, /* no file-operations */ @@ -66,7 +66,8 @@ }; static struct dentry *devtree_follow_link(struct dentry *dentry, - struct dentry *base) + struct dentry *base, + unsigned int follow) { struct inode *inode = dentry->d_inode; struct proc_dir_entry * de; @@ -74,7 +75,7 @@ de = (struct proc_dir_entry *) inode->u.generic_ip; link = (char *) de->data; - return lookup_dentry(link, base, 1); + return lookup_dentry(link, base, follow); } static int devtree_readlink(struct dentry *dentry, char *buffer, int buflen) diff -u --recursive --new-file v2.1.122/linux/fs/proc/root.c linux/fs/proc/root.c --- v2.1.122/linux/fs/proc/root.c Wed Aug 26 11:37:43 1998 +++ linux/fs/proc/root.c Sat Sep 19 13:44:48 1998 @@ -55,9 +55,6 @@ NULL /* can't fsync */ }; -int proc_readlink(struct dentry * dentry, char * buffer, int buflen); -struct dentry * proc_follow_link(struct dentry *dentry, struct dentry *base); - /* * proc directories can do almost nothing.. */ @@ -388,12 +385,13 @@ } static struct dentry * proc_self_follow_link(struct dentry *dentry, - struct dentry *base) + struct dentry *base, + unsigned int follow) { char tmp[30]; sprintf(tmp, "%d", current->pid); - return lookup_dentry(tmp, base, 1); + return lookup_dentry(tmp, base, follow); } int proc_readlink(struct dentry * dentry, char * buffer, int buflen) @@ -420,7 +418,7 @@ return len; } -struct dentry * proc_follow_link(struct dentry * dentry, struct dentry *base) +struct dentry * proc_follow_link(struct dentry * dentry, struct dentry *base, unsigned int follow) { struct inode *inode = dentry->d_inode; struct proc_dir_entry * de; @@ -435,7 +433,7 @@ if (de->readlink_proc) len = de->readlink_proc(de, page); - d = lookup_dentry(page, base, 1); + d = lookup_dentry(page, base, follow); free_page((unsigned long) page); return d; } diff -u --recursive --new-file v2.1.122/linux/fs/romfs/inode.c linux/fs/romfs/inode.c --- v2.1.122/linux/fs/romfs/inode.c Thu Aug 27 19:56:30 1998 +++ linux/fs/romfs/inode.c Sat Sep 19 13:45:18 1998 @@ -451,7 +451,8 @@ } static struct dentry *romfs_follow_link(struct dentry *dentry, - struct dentry *base) + struct dentry *base, + unsigned int follow) { struct inode *inode = dentry->d_inode; char *link; @@ -470,7 +471,7 @@ } else link[len] = 0; - dentry = lookup_dentry(link, base, 1); + dentry = lookup_dentry(link, base, follow); kfree(link); if (0) { diff -u --recursive --new-file v2.1.122/linux/fs/super.c linux/fs/super.c --- v2.1.122/linux/fs/super.c Thu Sep 17 17:53:38 1998 +++ linux/fs/super.c Sat Sep 26 13:14:03 1998 @@ -868,17 +868,19 @@ struct vfsmount *vfsmnt; int error; - down(&mount_sem); error = -EACCES; if (!(flags & MS_RDONLY) && dev && is_read_only(dev)) goto out; - /*flags |= MS_RDONLY;*/ + /* + * Do the lookup first to force automounting. + */ dir_d = namei(dir_name); error = PTR_ERR(dir_d); if (IS_ERR(dir_d)) goto out; + down(&mount_sem); error = -ENOTDIR; if (!S_ISDIR(dir_d->d_inode->i_mode)) goto dput_and_out; @@ -906,18 +908,16 @@ error = -ENOMEM; vfsmnt = add_vfsmnt(sb, dev_name, dir_name); - if (!vfsmnt) - goto dput_and_out; - d_mount(dir_d, sb->s_root); - error = 0; /* we don't dput(dir_d) - see umount */ - -out: - up(&mount_sem); - return error; + if (vfsmnt) { + d_mount(dget(dir_d), sb->s_root); + error = 0; + } dput_and_out: dput(dir_d); - goto out; + up(&mount_sem); +out: + return error; } diff -u --recursive --new-file v2.1.122/linux/fs/sysv/symlink.c linux/fs/sysv/symlink.c --- v2.1.122/linux/fs/sysv/symlink.c Sun Jan 4 00:53:41 1998 +++ linux/fs/sysv/symlink.c Sat Sep 19 13:45:42 1998 @@ -21,7 +21,7 @@ #include static int sysv_readlink(struct dentry *, char *, int); -static struct dentry *sysv_follow_link(struct dentry *, struct dentry *); +static struct dentry *sysv_follow_link(struct dentry *, struct dentry *, unsigned int); /* * symlinks can't do much... @@ -47,7 +47,8 @@ }; static struct dentry *sysv_follow_link(struct dentry * dentry, - struct dentry * base) + struct dentry * base, + unsigned int follow) { struct inode *inode = dentry->d_inode; struct buffer_head * bh; @@ -58,7 +59,7 @@ return ERR_PTR(-EIO); } UPDATE_ATIME(inode); - base = lookup_dentry(bh->b_data, base, 1); + base = lookup_dentry(bh->b_data, base, follow); brelse(bh); return base; } diff -u --recursive --new-file v2.1.122/linux/fs/ufs/symlink.c linux/fs/ufs/symlink.c --- v2.1.122/linux/fs/ufs/symlink.c Sat Sep 5 16:46:41 1998 +++ linux/fs/ufs/symlink.c Sat Sep 19 13:46:01 1998 @@ -43,7 +43,7 @@ static struct dentry * ufs_follow_link(struct dentry * dentry, - struct dentry * base) + struct dentry * base, unsigned int follow) { struct inode * inode; struct buffer_head * bh; @@ -67,7 +67,7 @@ link = (char *) inode->u.ufs_i.i_u1.i_symlink; } UPDATE_ATIME(inode); - base = lookup_dentry(link, base, 1); + base = lookup_dentry(link, base, follow); if (bh) brelse(bh); UFSD(("EXIT\n")) diff -u --recursive --new-file v2.1.122/linux/fs/umsdos/dir.c linux/fs/umsdos/dir.c --- v2.1.122/linux/fs/umsdos/dir.c Thu Sep 17 17:53:38 1998 +++ linux/fs/umsdos/dir.c Fri Sep 25 16:30:07 1998 @@ -20,6 +20,7 @@ #include #define UMSDOS_SPECIAL_DIRFPOS 3 +extern struct dentry *saved_root; extern struct inode *pseudo_root; /* #define UMSDOS_DEBUG_VERBOSE 1 */ @@ -53,42 +54,6 @@ NULL, }; -/* - * This needs to have the parent dentry passed to it. - * N.B. Try to get rid of this soon! - */ -int compat_msdos_create (struct inode *dir, const char *name, int len, - int mode, struct inode **inode) -{ - int ret; - struct dentry *dentry, *d_dir; - - check_inode (dir); - ret = -ENOMEM; - d_dir = geti_dentry (dir); - if (!d_dir) { -printk(KERN_ERR "compat_msdos_create: flaky i_dentry didn't work\n"); - goto out; - } - dget(d_dir); - dentry = creat_dentry (name, len, NULL, d_dir); - dput(d_dir); - if (!dentry) - goto out; - - check_dentry_path (dentry, "compat_msdos_create START"); - ret = msdos_create (dir, dentry, mode); - check_dentry_path (dentry, "compat_msdos_create END"); - if (ret) - goto out; - if (inode != NULL) - *inode = dentry->d_inode; - - check_inode (dir); -out: - return ret; -} - /* * So grep * doesn't complain in the presence of directories. @@ -203,9 +168,11 @@ ret = PTR_ERR(demd); if (IS_ERR(demd)) goto out_end; - ret = 0; + ret = -EIO; if (!demd->d_inode) { -printk("no EMD file??\n"); + printk(KERN_WARNING + "umsdos_readir_x: EMD file %s/%s not found\n", + demd->d_parent->d_name.name, demd->d_name.name); goto out_dput; } @@ -404,18 +371,17 @@ * does this automatically. */ -void umsdos_lookup_patch (struct inode *dir, struct inode *inode, - struct umsdos_dirent *entry, off_t emd_pos) +void umsdos_lookup_patch_new(struct dentry *dentry, struct umsdos_info *info) { - if (inode->i_sb != dir->i_sb) - goto out; - if (umsdos_isinit (inode)) - goto out; + struct inode *inode = dentry->d_inode; + struct umsdos_dirent *entry = &info->entry; - if (S_ISDIR (inode->i_mode)) - umsdos_lockcreate (inode); - if (umsdos_isinit (inode)) - goto out_unlock; + /* + * This part of the initialization depends only on i_patched. + */ + if (inode->u.umsdos_i.i_patched) + goto out; + inode->u.umsdos_i.i_patched = 1; if (S_ISREG (entry->mode)) entry->mtime = inode->i_mtime; @@ -444,150 +410,18 @@ "UMSDOS: lookup_patch entry->nlink < 1 ???\n"); } } - umsdos_patch_inode (inode, dir, emd_pos); + /* + * The mode may have changed, so patch the inode again. + */ + umsdos_patch_dentry_inode(dentry, info->f_pos); + umsdos_set_dirinfo_new(dentry, info->f_pos); -out_unlock: - if (S_ISDIR (inode->i_mode)) - umsdos_unlockcreate (inode); - if (inode->u.umsdos_i.i_emd_owner == 0) - printk (KERN_WARNING "UMSDOS: emd_owner still 0?\n"); out: return; } /* - * The preferred interface to the above routine ... - */ -void umsdos_lookup_patch_new(struct dentry *dentry, struct umsdos_dirent *entry, - off_t emd_pos) -{ - umsdos_lookup_patch(dentry->d_parent->d_inode, dentry->d_inode, entry, - emd_pos); -} - - -struct UMSDOS_DIRENT_K { - off_t f_pos; /* will hold the offset of the entry in EMD */ - ino_t ino; -}; - - -/* - * Just to record the offset of one entry. - */ - -static int umsdos_filldir_k ( void *buf, - const char *name, - int len, - off_t offset, - ino_t ino) -{ - struct UMSDOS_DIRENT_K *d = (struct UMSDOS_DIRENT_K *) buf; - - d->f_pos = offset; - d->ino = ino; - return 0; -} - -struct UMSDOS_DIR_SEARCH { - struct umsdos_dirent *entry; - int found; - ino_t search_ino; -}; - -static int umsdos_dir_search ( void *buf, - const char *name, - int len, - off_t offset, - ino_t ino) -{ - int ret = 0; - struct UMSDOS_DIR_SEARCH *d = (struct UMSDOS_DIR_SEARCH *) buf; - - if (d->search_ino == ino) { - d->found = 1; - memcpy (d->entry->name, name, len); - d->entry->name[len] = '\0'; - d->entry->name_len = len; - ret = 1; /* So fat_readdir will terminate */ - } - return ret; -} - - - -/* - * Locate the directory entry for a dentry in its parent directory. - * Return 0 or a negative error code. - * - * Normally, this function must succeed. It means a strange corruption - * in the file system if not. - */ - -int umsdos_dentry_to_entry(struct dentry *dentry, struct umsdos_dirent *entry) -{ - struct dentry *parent = dentry->d_parent; - struct inode *inode = dentry->d_inode; - int ret = -ENOENT, err; - struct file filp; - struct UMSDOS_DIR_SEARCH bufsrch; - struct UMSDOS_DIRENT_K bufk; - - if (pseudo_root && inode == pseudo_root) { - /* - * Quick way to find the name. - * Also umsdos_readdir_x won't show /linux anyway - */ - memcpy (entry->name, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN + 1); - entry->name_len = UMSDOS_PSDROOT_LEN; - ret = 0; - goto out; - } - - /* initialize the file */ - fill_new_filp (&filp, parent); - - if (!umsdos_have_emd(parent)) { - /* This is a DOS directory. */ - filp.f_pos = 0; - bufsrch.entry = entry; - bufsrch.search_ino = inode->i_ino; - fat_readdir (&filp, &bufsrch, umsdos_dir_search); - if (bufsrch.found) { - ret = 0; - inode->u.umsdos_i.i_emd_owner = 0; -if (!S_ISDIR(inode->i_mode)) -printk("UMSDOS: %s/%s not a directory!\n", -dentry->d_parent->d_name.name, dentry->d_name.name); - /* N.B. why call this? not always a dir ... */ - umsdos_setup_dir(dentry); - } - goto out; - } - - /* skip . and .. see umsdos_readdir_x() */ - filp.f_pos = UMSDOS_SPECIAL_DIRFPOS; - while (1) { - err = umsdos_readdir_x (parent->d_inode, &filp, &bufk, 1, - entry, 0, umsdos_filldir_k); - if (err < 0) { - printk ("umsdos_dentry_to_entry: ino=%ld, err=%d\n", - inode->i_ino, err); - break; - } - if (bufk.ino == inode->i_ino) { - ret = 0; - umsdos_lookup_patch_new(dentry, entry, bufk.f_pos); - break; - } - } -out: - return ret; -} - - -/* * Return != 0 if an entry is the pseudo DOS entry in the pseudo root. */ @@ -627,8 +461,6 @@ int umsdos_lookup_x (struct inode *dir, struct dentry *dentry, int nopseudo) { - const char *name = dentry->d_name.name; - int len = dentry->d_name.len; struct dentry *dret = NULL; struct inode *inode; int ret = -ENOENT; @@ -640,28 +472,13 @@ #endif umsdos_startlookup (dir); - /* this shouldn't happen ... */ - if (len == 1 && name[0] == '.') { - printk("umsdos_lookup_x: UMSDOS broken, please report!\n"); - goto out; - } - - /* this shouldn't happen ... */ - if (len == 2 && name[0] == '.' && name[1] == '.') { - printk("umsdos_lookup_x: UMSDOS broken, please report!\n"); - goto out; - } - if (umsdos_is_pseudodos (dir, dentry)) { /* #Specification: pseudo root / lookup(DOS) * A lookup of DOS in the pseudo root will always succeed * and return the inode of the real root. */ - inode = iget(dir->i_sb, UMSDOS_ROOT_INO); - if (inode) - goto out_add; - ret = -ENOMEM; - goto out; + inode = saved_root->d_inode; + goto out_add; } ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info); @@ -693,7 +510,7 @@ inode = dret->d_inode; if (!inode) goto out_remove; - umsdos_lookup_patch_new(dret, &info.entry, info.f_pos); + umsdos_lookup_patch_new(dret, &info); #ifdef UMSDOS_DEBUG_VERBOSE printk("umsdos_lookup_x: found %s/%s, ino=%ld\n", dret->d_parent->d_name.name, dret->d_name.name, dret->d_inode->i_ino); @@ -726,6 +543,7 @@ * mode. */ printk(KERN_WARNING "umsdos_lookup_x: untested, inode == Pseudo_root\n"); + ret = -ENOENT; goto out_dput; } diff -u --recursive --new-file v2.1.122/linux/fs/umsdos/emd.c linux/fs/umsdos/emd.c --- v2.1.122/linux/fs/umsdos/emd.c Thu Sep 17 17:53:38 1998 +++ linux/fs/umsdos/emd.c Fri Sep 25 16:30:07 1998 @@ -189,7 +189,9 @@ /* - * Create the EMD dentry for a directory. + * Lookup the EMD dentry for a directory. + * + * Note: the caller must hold a lock on the parent directory. */ struct dentry *umsdos_get_emd_dentry(struct dentry *parent) { @@ -202,6 +204,8 @@ /* * Check whether a directory has an EMD file. + * + * Note: the caller must hold a lock on the parent directory. */ int umsdos_have_emd(struct dentry *dir) { @@ -219,11 +223,12 @@ /* * Create the EMD file for a directory if it doesn't * already exist. Returns 0 or an error code. + * + * Note: the caller must hold a lock on the parent directory. */ int umsdos_make_emd(struct dentry *parent) { struct dentry *demd = umsdos_get_emd_dentry(parent); - struct inode *inode; int err = PTR_ERR(demd); if (IS_ERR(demd)) { @@ -234,8 +239,7 @@ /* already created? */ err = 0; - inode = demd->d_inode; - if (inode) + if (demd->d_inode) goto out_set; Printk(("umsdos_make_emd: creating EMD %s/%s\n", @@ -244,15 +248,12 @@ err = msdos_create(parent->d_inode, demd, S_IFREG | 0777); if (err) { printk (KERN_WARNING - "UMSDOS: create %s/%s failed, err=%d\n", + "umsdos_make_emd: create %s/%s failed, err=%d\n", parent->d_name.name, demd->d_name.name, err); goto out_dput; } - inode = demd->d_inode; out_set: - parent->d_inode->u.umsdos_i.i_emd_dir = inode->i_ino; - /* Disable UMSDOS_notify_change() for EMD file */ - inode->u.umsdos_i.i_emd_owner = 0xffffffff; + parent->d_inode->u.umsdos_i.i_emd_dir = demd->d_inode->i_ino; out_dput: dput(demd); @@ -262,92 +263,6 @@ /* - * Locate the EMD file in a directory. - * - * Return NULL if error, dir->u.umsdos_i.emd_inode if OK. - * Caller must iput() returned inode when finished with it! - * Note: deprecated; get rid of this soon! - */ - -struct inode *umsdos_emd_dir_lookup (struct inode *dir, int creat) -{ - struct inode *ret = NULL; - struct dentry *d_dir=NULL, *dlook=NULL; - int rv; - - Printk ((KERN_DEBUG "Entering umsdos_emd_dir_lookup\n")); - if (!dir) { - printk (KERN_CRIT "umsdos_emd_dir_lookup: FATAL, dir=NULL!\n"); - goto out; - } - check_inode (dir); - - if (dir->u.umsdos_i.i_emd_dir != 0) { - ret = iget (dir->i_sb, dir->u.umsdos_i.i_emd_dir); - Printk (("umsdos_emd_dir_lookup: deja trouve %ld %p\n", - dir->u.umsdos_i.i_emd_dir, ret)); - goto out; - } - - PRINTK ((KERN_DEBUG "umsdos /mn/: Looking for %.*s -", - UMSDOS_EMD_NAMELEN, UMSDOS_EMD_FILE)); - - d_dir = geti_dentry (dir); - if (!d_dir) { -printk("UMSDOS: flaky i_dentry hack failed\n"); - goto out; - } - dlook = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL, d_dir); - if (!dlook) - goto out; - rv = msdos_lookup (dir, dlook); - - PRINTK ((KERN_DEBUG "-returned %d\n", rv)); - Printk ((KERN_INFO "emd_dir_lookup ")); - - ret = dlook->d_inode; - if (ret) { - Printk (("Found --linux ")); - dir->u.umsdos_i.i_emd_dir = ret->i_ino; - ret->i_count++; /* we'll need the inode */ - check_inode (ret); - } else if (creat) { - int code; - - Printk ((" * ERROR * /mn/: creat not yet implemented? not fixed? ")); - Printk (("avant create ")); - - check_inode (ret); - code = compat_msdos_create (dir, UMSDOS_EMD_FILE, - UMSDOS_EMD_NAMELEN, - S_IFREG | 0777, &ret); - check_inode (ret); - Printk (("Creat EMD code %d ret %p ", code, ret)); - if (ret != NULL) { - Printk ((" ino=%lu", ret->i_ino)); - dir->u.umsdos_i.i_emd_dir = ret->i_ino; - } else { - printk (KERN_WARNING "UMSDOS: Can't create EMD file\n"); - } - } - dput(dlook); - - if (ret != NULL) { - /* Disable UMSDOS_notify_change() for EMD file */ - ret->u.umsdos_i.i_emd_owner = 0xffffffff; - } - -out: -#if UMS_DEBUG - Printk ((KERN_DEBUG "umsdos_emd_dir_lookup returning %p /mn/\n", ret)); - if (ret != NULL) - Printk ((KERN_DEBUG " returning ino=%lu\n", ret->i_ino)); -#endif - return ret; -} - - -/* * Read an entry from the EMD file. * Support variable length record. * Return -EIO if error, 0 if OK. @@ -387,6 +302,8 @@ /* * Write an entry in the EMD file. * Return 0 if OK, -EIO if some error. + * + * Note: the caller must hold a lock on the parent directory. */ static int umsdos_writeentry (struct dentry *parent, struct umsdos_info *info, int free_entry) @@ -405,8 +322,9 @@ /* make sure there's an EMD file */ ret = -EIO; if (!emd_dentry->d_inode) { -printk("umsdos_writeentry: no EMD file in %s/%s\n", -parent->d_parent->d_name.name, parent->d_name.name); + printk(KERN_WARNING + "umsdos_writeentry: no EMD file in %s/%s\n", + parent->d_parent->d_name.name, parent->d_name.name); goto out_dput; } @@ -468,6 +386,8 @@ * Unread bytes are simply moved to the beginning. * * Return -ENOENT if EOF, 0 if OK, a negative error code if any problem. + * + * Note: the caller must hold a lock on the parent directory. */ static int umsdos_fillbuf (struct find_buffer *buf) @@ -518,6 +438,7 @@ * All this to say that umsdos_writeentry must be called after this * function since it relies on the f_pos field of info. * + * Note: the caller must hold a lock on the parent directory. */ /* #Specification: EMD file structure * The EMD file uses a fairly simple layout. It is made of records diff -u --recursive --new-file v2.1.122/linux/fs/umsdos/inode.c linux/fs/umsdos/inode.c --- v2.1.122/linux/fs/umsdos/inode.c Thu Sep 17 17:53:38 1998 +++ linux/fs/umsdos/inode.c Fri Sep 25 16:30:07 1998 @@ -23,35 +23,11 @@ extern struct inode_operations umsdos_rdir_inode_operations; +struct dentry *saved_root = NULL; /* Original root if changed */ struct inode *pseudo_root = NULL; /* Useful to simulate the pseudo DOS */ /* directory. See UMSDOS_readdir_x() */ - -/* - * returns inode->i_dentry - * Note: Deprecated; won't work reliably - */ - -struct dentry *geti_dentry (struct inode *inode) -{ - struct dentry *ret; - - if (!inode) { - printk (KERN_ERR "geti_dentry: ERROR: inode is NULL!\n"); - return NULL; - } - if (list_empty(&inode->i_dentry)) { - printk (KERN_WARNING - "geti_dentry: WARNING: no dentry for inode %ld\n", - inode->i_ino); - return NULL; - } - ret = list_entry (inode->i_dentry.next, struct dentry, d_alias); - - PRINTK ((KERN_DEBUG "geti_dentry : inode %lu, dentry is %s/%s\n", - inode->i_ino, ret->d_parent->d_name.name, ret->d_name.name)); - return ret; -} +static struct dentry *check_pseudo_root(struct super_block *); /* @@ -70,61 +46,6 @@ } -/* - * makes dentry. for name name with length len. - * if inode is not NULL, puts it also. - * Note: Deprecated; use umsdos_lookup_dentry - */ - -struct dentry *creat_dentry (const char *name, const int len, - struct inode *inode, struct dentry *parent) -{ -/* FIXME /mn/: parent is not passed many times... if it is not, dentry should be destroyed before someone else gets to use it */ - - struct dentry *ret; - struct qstr qname; - - if (inode) - Printk ((KERN_DEBUG "creat_dentry: creating dentry with inode=%lu for %.*s\n", inode->i_ino, len, name)); - else - Printk ((KERN_DEBUG "creat_dentry: creating empty dentry for %.*s\n", len, name)); - - qname.name = name; - qname.len = len; - qname.hash = full_name_hash (name, len); - - ret = d_alloc (parent, &qname); /* create new dentry */ - - if (parent) { -#if 0 - Printk ((KERN_DEBUG "creat_dentry: cloning parent d_op !\n")); - ret->d_op = parent->d_op; -#else - ret->d_op = NULL; -#endif - } else { - ret->d_parent = ret; - Printk ((KERN_WARNING "creat_dentry: WARNING: NO parent! faking root! beware !\n")); - } - - - if (inode) { - /* try to fill it in if available. If available in - * parent->d_sb, d_alloc will add it automatically - */ - if (!ret->d_sb) ret->d_sb = inode->i_sb; - d_add (ret, inode); - } - - if (!ret->d_sb) { - printk (KERN_ERR "creat_dentry: ERROR: NO d_sb !\n"); - } else if (!ret->d_sb->s_dev) { - printk (KERN_WARNING "creat_dentry: WARNING: NO s_dev. Ugh. !\n"); - } - - return ret; -} - void UMSDOS_put_inode (struct inode *inode) { @@ -146,18 +67,23 @@ void UMSDOS_put_super (struct super_block *sb) { Printk ((KERN_DEBUG "UMSDOS_put_super: entering\n")); + if (saved_root) { + shrink_dcache_parent(saved_root); +printk("UMSDOS_put_super: freeing saved root, d_count=%d\n", +saved_root->d_count); + dput(saved_root); + saved_root = NULL; + pseudo_root = NULL; + } msdos_put_super (sb); MOD_DEC_USE_COUNT; } /* - * Complete the setup of an directory dentry. - * First, it completes the function pointers, then - * it locates the EMD file. If the EMD is there, then plug the + * Complete the setup of a directory dentry based on its + * EMD/non-EMD status. If it has an EMD, then plug the * umsdos function table. If not, use the msdos one. - * - * {i,d}_counts are untouched by this function. */ void umsdos_setup_dir(struct dentry *dir) { @@ -176,40 +102,6 @@ } } -/* - * Complete the setup of an directory inode. - * First, it completes the function pointers, then - * it locates the EMD file. If the EMD is there, then plug the - * umsdos function table. If not, use the msdos one. - * - * {i,d}_counts are untouched by this function. - * Note: Deprecated; use above function if possible. - */ -void umsdos_setup_dir_inode (struct inode *inode) -{ - struct inode *emd_dir; - - inode->u.umsdos_i.i_emd_dir = 0; - - Printk ((KERN_DEBUG - "umsdos_setup_dir_inode: Entering for inode=%lu\n", - inode->i_ino)); - check_inode (inode); - emd_dir = umsdos_emd_dir_lookup (inode, 0); - Printk ((KERN_DEBUG "umsdos_setup_dir_inode: " - "umsdos_emd_dir_lookup for inode=%lu returned %p\n", - inode->i_ino, emd_dir)); - check_inode (inode); - check_inode (emd_dir); - - inode->i_op = &umsdos_rdir_inode_operations; - if (emd_dir) { - Printk ((KERN_DEBUG "umsdos_setup_dir_inode: using EMD.\n")); - inode->i_op = &umsdos_dir_inode_operations; - iput (emd_dir); - } -} - /* * Add some info into an inode so it can find its owner quickly @@ -224,34 +116,11 @@ /* now check the EMD file */ demd = umsdos_get_emd_dentry(dentry->d_parent); - if (IS_ERR(demd)) { - goto out; - } - if (demd->d_inode) { - inode->u.umsdos_i.i_emd_owner = demd->d_inode->i_ino; + if (!IS_ERR(demd)) { + if (demd->d_inode) + inode->u.umsdos_i.i_emd_owner = demd->d_inode->i_ino; + dput(demd); } - dput (demd); -out: - return; -} - - -/* - * Add some info into an inode so it can find its owner quickly - * Note: Deprecated; use above function if possible. - */ -void umsdos_set_dirinfo (struct inode *inode, struct inode *dir, off_t f_pos) -{ - struct inode *emd_owner = umsdos_emd_dir_lookup (dir, 1); - - if (!emd_owner) - goto out; - Printk (("umsdos_set_dirinfo: emd_owner is %lu for dir %lu\n", - emd_owner->i_ino, dir->i_ino)); - inode->u.umsdos_i.i_emd_owner = emd_owner->i_ino; - inode->u.umsdos_i.pos = f_pos; - iput (emd_owner); -out: return; } @@ -262,28 +131,12 @@ */ int umsdos_isinit (struct inode *inode) { - return inode->u.umsdos_i.i_emd_owner != 0; + return 0; /* inode->u.umsdos_i.i_emd_owner != 0; */ } /* * Connect the proper tables in the inode and add some info. - * i_counts is not changed. - * - * This function is called very early to setup the inode, somewhat - * too early (called by UMSDOS_read_inode). At this point, we can't - * do too much, such as lookup up EMD files and so on. This causes - * confusion in the kernel. This is why some initialisation - * will be done when dir != NULL only. - * - * UMSDOS do run piggy back on top of msdos fs. It looks like something - * is missing in the VFS to accommodate stacked fs. Still unclear what - * (quite honestly). - * - * Well, maybe one! A new entry "may_unmount" which would allow - * the stacked fs to allocate some inode permanently and release - * them at the end. Doing that now introduce a problem. unmount - * always fail because some inodes are in use. */ /* #Specification: inode / umsdos info * The first time an inode is seen (inode->i_count == 1), @@ -291,88 +144,45 @@ * is tagged to this inode. It allows operations such as * notify_change to be handled. */ -void umsdos_patch_inode (struct inode *inode, struct inode *dir, off_t f_pos) +void umsdos_patch_dentry_inode(struct dentry *dentry, off_t f_pos) { - Printk ((KERN_DEBUG "Entering umsdos_patch_inode for inode=%lu\n", - inode->i_ino)); + struct inode *inode = dentry->d_inode; + +Printk (("umsdos_patch_dentry_inode: inode=%lu\n", inode->i_ino)); - if (umsdos_isinit (inode)) - goto already_init; + /* + * Classify the inode based on EMD/non-EMD status. + */ +Printk (("umsdos_patch_inode: call x_set_dirinfo(%p,%p,%lu)\n", +inode, dir, f_pos)); + umsdos_set_dirinfo_new(dentry, f_pos); inode->u.umsdos_i.i_emd_dir = 0; if (S_ISREG (inode->i_mode)) { if (MSDOS_SB (inode->i_sb)->cvf_format) { if (MSDOS_SB (inode->i_sb)->cvf_format->flags & CVF_USE_READPAGE) { -Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: setting i_op = umsdos_file_inode_operations_readpage\n")); inode->i_op = &umsdos_file_inode_operations_readpage; } else { -Printk ((KERN_DEBUG "umsdos_patch_inode: umsdos_file_inode_ops_no_bmap\n")); inode->i_op = &umsdos_file_inode_operations_no_bmap; } } else { if (inode->i_op->bmap != NULL) { -Printk ((KERN_DEBUG "umsdos_patch_inode: umsdos_file_inode_ops\n")); inode->i_op = &umsdos_file_inode_operations; } else { -Printk ((KERN_DEBUG "umsdos_patch_inode: umsdos_file_inode_ops_no_bmap\n")); inode->i_op = &umsdos_file_inode_operations_no_bmap; } } } else if (S_ISDIR (inode->i_mode)) { - if (dir != NULL) { - umsdos_setup_dir_inode (inode); - } + umsdos_setup_dir(dentry); } else if (S_ISLNK (inode->i_mode)) { - Printk ((KERN_DEBUG - "umsdos_patch_inode: umsdos_symlink_inode_ops\n")); inode->i_op = &umsdos_symlink_inode_operations; } else if (S_ISCHR (inode->i_mode)) { - Printk ((KERN_DEBUG "umsdos_patch_inode: chrdev_inode_ops\n")); inode->i_op = &chrdev_inode_operations; } else if (S_ISBLK (inode->i_mode)) { - Printk ((KERN_DEBUG "umsdos_patch_inode: blkdev_inode_ops\n")); inode->i_op = &blkdev_inode_operations; } else if (S_ISFIFO (inode->i_mode)) { - Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: uhm, init_fifo\n")); init_fifo (inode); } - if (dir != NULL) { - /* - * This is done last because it also control the - * status of umsdos_isinit() - */ - Printk ((KERN_DEBUG - "umsdos_patch_inode: call x_set_dirinfo(%p,%p,%lu)\n", - inode, dir, f_pos)); - umsdos_set_dirinfo (inode, dir, f_pos); - } - return; - -already_init: - if (dir != NULL) { - /* - * Test to see if the info is maintained. - * This should be removed when the file system will be proven. - */ - struct inode *emd_owner = umsdos_emd_dir_lookup (dir, 1); - if (!emd_owner) - goto out; - if (emd_owner->i_ino != inode->u.umsdos_i.i_emd_owner) { -printk ("UMSDOS: *** EMD_OWNER ??? *** ino = %ld %ld <> %ld ", -inode->i_ino, emd_owner->i_ino, inode->u.umsdos_i.i_emd_owner); - } - iput (emd_owner); - out: - return; - } -} - -/* - * Patch the inode in a dentry. - */ -void umsdos_patch_dentry_inode(struct dentry *dentry, off_t f_pos) -{ - umsdos_patch_inode(dentry->d_inode, dentry->d_parent->d_inode, f_pos); } @@ -382,40 +192,43 @@ /* #Specification: Inode / post initialisation * To completely initialise an inode, we need access to the owner * directory, so we can locate more info in the EMD file. This is - * not available the first time the inode is access, we use + * not available the first time the inode is accessed, so we use * a value in the inode to tell if it has been finally initialised. * - * At first, we have tried testing i_count but it was causing - * problem. It is possible that two or more process use the - * newly accessed inode. While the first one block during - * the initialisation (probably while reading the EMD file), the - * others believe all is well because i_count > 1. They go banana - * with a broken inode. See umsdos_lookup_patch and umsdos_patch_inode. + * New inodes are obtained by the lookup and create routines, and + * each of these must ensure that the inode gets patched. */ void UMSDOS_read_inode (struct inode *inode) { PRINTK ((KERN_DEBUG "UMSDOS_read_inode %p ino = %lu ", inode, inode->i_ino)); msdos_read_inode (inode); - PRINTK (("ino after msdos_read_inode= %lu i_count=%d\n", - inode->i_ino, inode->i_count)); - if (S_ISDIR (inode->i_mode) - && (inode->u.umsdos_i.u.dir_info.creating != 0 - || inode->u.umsdos_i.u.dir_info.looking != 0 - || waitqueue_active (&inode->u.umsdos_i.u.dir_info.p))) { - Printk (("read inode %d %d %p\n" - ,inode->u.umsdos_i.u.dir_info.creating - ,inode->u.umsdos_i.u.dir_info.looking - ,inode->u.umsdos_i.u.dir_info.p)); - } - /* N.B. Defer this until we have a dentry ... */ - umsdos_patch_inode (inode, NULL, 0); + /* inode needs patching */ + inode->u.umsdos_i.i_patched = 0; } +int umsdos_notify_change_locked(struct dentry *, struct iattr *); +/* + * lock the parent dir before starting ... + */ int UMSDOS_notify_change (struct dentry *dentry, struct iattr *attr) { + struct inode *dir = dentry->d_parent->d_inode; + int ret; + + down(&dir->i_sem); + ret = umsdos_notify_change_locked(dentry, attr); + up(&dir->i_sem); + return ret; +} + +/* + * Must be called with the parent lock held. + */ +int umsdos_notify_change_locked(struct dentry *dentry, struct iattr *attr) +{ struct inode *inode = dentry->d_inode; struct dentry *demd; int ret; @@ -433,16 +246,15 @@ } if (inode->i_nlink == 0) - goto out_nolink; - + goto out; if (inode->i_ino == UMSDOS_ROOT_INO) - goto out_nolink; + goto out; /* get the EMD file dentry */ demd = umsdos_get_emd_dentry(dentry->d_parent); ret = PTR_ERR(demd); if (IS_ERR(demd)) - goto out_nolink; + goto out; ret = -EPERM; if (!demd->d_inode) { printk(KERN_WARNING @@ -509,10 +321,9 @@ out_dput: dput(demd); -out_nolink: +out: if (ret == 0) inode_setattr (inode, attr); -out: return ret; } @@ -562,7 +373,7 @@ int silent) { struct super_block *res; - struct inode *pseudo = NULL; + struct dentry *new_root; MOD_INC_USE_COUNT; MSDOS_SB(sb)->options.isvfat = 0; @@ -583,14 +394,19 @@ /* install our dentry operations ... */ sb->s_root->d_op = &umsdos_dentry_operations; - pseudo = sb->s_root->d_inode; - umsdos_setup_dir(sb->s_root); + umsdos_patch_dentry_inode(sb->s_root, 0); -#if 0 - if (pseudo) { - pseudo_root_stuff(); + /* Check whether to change to the /linux root */ + new_root = check_pseudo_root(sb); + if (new_root) { + pseudo_root = new_root->d_inode; + /* sanity check */ + if (new_root->d_op != &umsdos_dentry_operations) + printk("umsdos_read_super: pseudo-root wrong ops!\n"); + saved_root = sb->s_root; + sb->s_root = new_root; + printk(KERN_INFO "UMSDOS: changed to alternate root\n"); } -#endif /* if d_count is not 1, mount will fail with -EBUSY! */ if (sb->s_root->d_count > 1) { @@ -606,78 +422,50 @@ } /* - * FIXME URGENT: - * disable pseudo root-for the moment of testing. - * re-enable this before release ! + * Check for an alternate root if we're the root device. */ -#if 0 -void pseudo_root_stuff(void) +static struct dentry *check_pseudo_root(struct super_block *sb) { - struct dentry *root, *etc, *etc_rc, *sbin, *init = NULL; - - root = creat_dentry (UMSDOS_PSDROOT_NAME, - strlen (UMSDOS_PSDROOT_NAME), - NULL, res->s_root); - sbin = creat_dentry ("sbin", 4, NULL, root); - - Printk ((KERN_DEBUG "Mounting root\n")); - if (msdos_lookup (pseudo, root) == 0 - && (root->d_inode != NULL) - && S_ISDIR (root->d_inode->i_mode)) { - - int pseudo_ok = 0; - -Printk ((KERN_DEBUG "/%s is there\n", UMSDOS_PSDROOT_NAME)); - etc = creat_dentry ("etc", 3, NULL, root); + struct dentry *root, *init; + /* + * Check whether we're mounted as the root device. + * If so, this should be the only superblock. + */ + if (sb->s_list.next->next != &sb->s_list) + goto out_noroot; +printk("check_pseudo_root: mounted as root\n"); + + root = lookup_dentry(UMSDOS_PSDROOT_NAME, dget(sb->s_root), 0); + if (IS_ERR(root)) + goto out_noroot; + if (!root->d_inode) + goto out_dput; +printk("check_pseudo_root: found %s/%s\n", +root->d_parent->d_name.name, root->d_name.name); - if (msdos_lookup (pseudo, etc) == 0 - && S_ISDIR (etc->d_inode->i_mode)) { - -Printk ((KERN_DEBUG "/%s/etc is there\n", UMSDOS_PSDROOT_NAME)); - - init = creat_dentry ("init", 4, NULL, etc); - etc_rc = creat_dentry ("rc", 2, NULL, etc); - - if ((msdos_lookup (pseudo, init) == 0 - && S_ISREG (init->d_inode->i_mode)) - || (msdos_lookup (pseudo, etc_rc) == 0 - && S_ISREG (etc_rc->d_inode->i_mode))) { - pseudo_ok = 1; - } + /* look for /sbin/init */ + init = lookup_dentry("sbin/init", dget(root), 0); + if (!IS_ERR(init)) { + if (init->d_inode) + goto root_ok; + dput(init); + } + /* check for other files? */ + goto out_dput; + +root_ok: +printk("check_pseudo_root: found %s/%s, enabling pseudo-root\n", +init->d_parent->d_name.name, init->d_name.name); + dput(init); + return root; - /* FIXME !!!!!! */ - /* iput(init); */ - /* iput(rc); */ - } - if (!pseudo_ok - /* && msdos_lookup (pseudo, "sbin", 4, sbin)==0 */ - && msdos_lookup (pseudo, sbin) == 0 - && S_ISDIR (sbin->d_inode->i_mode)) { - -Printk ((KERN_DEBUG "/%s/sbin is there\n", UMSDOS_PSDROOT_NAME)); - if (msdos_lookup (pseudo, init) == 0 - && S_ISREG (init->d_inode->i_mode)) { - pseudo_ok = 1; - } - /* FIXME !!! - * iput (init); */ - } - if (pseudo_ok) { - umsdos_setup_dir_inode (pseudo); -Printk ((KERN_INFO "Activating pseudo root /%s\n", UMSDOS_PSDROOT_NAME)); - pseudo_root = pseudo; - inc_count (pseudo); - pseudo = NULL; - } - /* FIXME - * - * iput (sbin); - * iput (etc); - */ - } + /* Alternate root not found ... */ +out_dput: + dput(root); +out_noroot: + return NULL; } -#endif static struct file_system_type umsdos_fs_type = diff -u --recursive --new-file v2.1.122/linux/fs/umsdos/ioctl.c linux/fs/umsdos/ioctl.c --- v2.1.122/linux/fs/umsdos/ioctl.c Thu Sep 17 17:53:38 1998 +++ linux/fs/umsdos/ioctl.c Fri Sep 25 16:30:07 1998 @@ -262,7 +262,7 @@ * is in the dos_dirent.name field and the destination * is in umsdos_dirent.name field. * - * This ioctl allows umssync to rename a mangle file + * This ioctl allows umssync to rename a mangled file * name before syncing it back in the EMD. */ old_dentry = umsdos_lookup_dentry (dentry, @@ -282,7 +282,6 @@ ret = msdos_rename (dir, old_dentry, dir, new_dentry); dput(new_dentry); } - d_drop(old_dentry); dput(old_dentry); goto out; } @@ -306,6 +305,11 @@ data.umsdos_dirent.name_len, &info); ret = umsdos_delentry (dentry, &info, S_ISDIR (data.umsdos_dirent.mode)); + if (ret) { + printk(KERN_WARNING + "umsdos_ioctl: delentry %s/%s failed, ret=%d\n", + dentry->d_name.name, info.entry.name, ret); + } goto out; } else if (cmd == UMSDOS_UNLINK_DOS) { @@ -324,9 +328,11 @@ if (IS_ERR(temp)) goto out; ret = -ENOENT; - if (temp->d_inode) - ret = msdos_unlink (dir, temp); - d_drop(temp); + if (temp->d_inode) { + ret = -EISDIR; + if (!S_ISDIR(temp->d_inode->i_mode)) + ret = msdos_unlink (dir, temp); + } dput (temp); goto out; } @@ -346,9 +352,11 @@ if (IS_ERR(temp)) goto out; ret = -ENOENT; - if (temp->d_inode) - ret = msdos_rmdir (dir, temp); - d_drop(temp); + if (temp->d_inode) { + ret = -ENOTDIR; + if (S_ISDIR(temp->d_inode->i_mode)) + ret = msdos_rmdir (dir, temp); + } dput (temp); goto out; @@ -385,7 +393,6 @@ sizeof (data.stat))) ret = 0; } - d_drop(dret); dput(dret); goto out; } diff -u --recursive --new-file v2.1.122/linux/fs/umsdos/namei.c linux/fs/umsdos/namei.c --- v2.1.122/linux/fs/umsdos/namei.c Thu Sep 17 17:53:38 1998 +++ linux/fs/umsdos/namei.c Fri Sep 25 16:30:07 1998 @@ -177,17 +177,15 @@ static int is_sticky(struct inode *dir, int uid) { return !((dir->i_mode & S_ISVTX) == 0 || - capable (CAP_FOWNER) || current->fsuid == uid || - current->fsuid == dir->i_uid); + current->fsuid == dir->i_uid || + capable (CAP_FOWNER)); } static int umsdos_nevercreat (struct inode *dir, struct dentry *dentry, int errcod) { - const char *name = dentry->d_name.name; - int len = dentry->d_name.len; int ret = 0; if (umsdos_is_pseudodos (dir, dentry)) { @@ -198,20 +196,6 @@ * The pseudo sub-directory /DOS can't be removed! * EPERM is returned. */ - ret = -EPERM; - ret = errcod; - } else if (name[0] == '.' - && (len == 1 || (len == 2 && name[1] == '.'))) { - /* #Specification: create / . and .. - * If one try to creates . or .., it always fail and return - * EEXIST. - * - * If one try to delete . or .., it always fail and return - * EPERM. - * - * This should be test at the VFS layer level to avoid - * duplicating this in all file systems. Any comments ? - */ ret = errcod; } return ret; @@ -269,10 +253,9 @@ info.entry.gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid; info.entry.ctime = info.entry.atime = info.entry.mtime = CURRENT_TIME; info.entry.nlink = 1; - umsdos_lockcreate (dir); ret = umsdos_newentry (dentry->d_parent, &info); if (ret) - goto out_unlock; + goto out; /* do a real lookup to get the short name dentry */ fake = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname, @@ -281,43 +264,49 @@ if (IS_ERR(fake)) goto out_remove; + /* keep the short name anonymous ... */ + if (dentry != fake) + d_drop(fake); + /* should not exist yet ... */ ret = -EEXIST; if (fake->d_inode) - goto out_remove; + goto out_remove_dput; ret = msdos_create (dir, fake, S_IFREG | 0777); if (ret) - goto out_remove; + goto out_remove_dput; + inode = fake->d_inode; /* * Note! The long and short name might be the same, * so check first before doing the instantiate ... */ if (dentry != fake) { - inode = fake->d_inode; inode->i_count++; d_instantiate (dentry, inode); } - umsdos_lookup_patch_new(dentry, &info.entry, info.f_pos); - goto out_dput; + dput(fake); + if (inode->i_count > 1) { + printk(KERN_WARNING + "umsdos_create_any: %s/%s, ino=%ld, icount=%d??\n", + dentry->d_parent->d_name.name, dentry->d_name.name, + inode->i_ino, inode->i_count); + } + umsdos_lookup_patch_new(dentry, &info); +out: + return ret; + + /* Creation failed ... remove the EMD entry */ +out_remove_dput: + dput(fake); out_remove: if (ret == -EEXIST) printk(KERN_WARNING "UMSDOS: out of sync, deleting %s/%s\n", dentry->d_parent->d_name.name, info.fake.fname); umsdos_delentry (dentry->d_parent, &info, S_ISDIR (info.entry.mode)); - -out_dput: - /* N.B. any value in keeping short name dentries? */ - if (dentry != fake) - d_drop(fake); - dput(fake); - -out_unlock: - umsdos_unlockcreate (dir); -out: - return ret; + goto out; } /* @@ -340,7 +329,6 @@ static void umsdos_ren_init (struct umsdos_info *new_info, struct umsdos_info *old_info) { - /* != 0, this is the value of flags */ new_info->entry.mode = old_info->entry.mode; new_info->entry.rdev = old_info->entry.rdev; new_info->entry.uid = old_info->entry.uid; @@ -373,7 +361,8 @@ struct inode *new_dir, struct dentry *new_dentry, int flags) { - struct dentry *old, *new, *old_emd, *new_target = NULL; + struct inode *old_inode = old_dentry->d_inode; + struct dentry *old, *new, *old_emd; int err, ret, rehash = 0; struct umsdos_info old_info; struct umsdos_info new_info; @@ -407,8 +396,12 @@ /* check sticky bit on old_dir */ ret = -EPERM; - if (is_sticky(old_dir, old_info.entry.uid)) + if (is_sticky(old_dir, old_info.entry.uid)) { +printk("umsdos_rename_f: %s/%s old sticky bit, fsuid=%d, uid=%d, dir=%d\n", +old_dentry->d_parent->d_name.name, old_info.entry.name, +current->fsuid, old_info.entry.uid, old_dir->i_uid); goto out_unlock; + } /* * Check whether the new_name already exists, and @@ -470,6 +463,34 @@ /* short and long name dentries match? */ if (old == old_dentry) dput(old); + else { + /* make sure it's the same inode! */ + ret = -ENOENT; + if (old->d_inode != old_inode) + goto out_dput; + /* + * A cross-directory move with different short and long + * names has nasty complications: msdos-fs will need to + * change inodes, so we must check whether the original + * dentry is busy, and if the rename succeeds the short + * dentry will come back with a different inode. + * + * To handle this, we drop the dentry and free the inode, + * and then pick up the new inode after the rename. + */ + if (old_dir != new_dir) { + ret = -EBUSY; + if (old_dentry->d_count > 1) { +printk("umsdos_rename_f: old dentry %s/%s busy, d_count=%d\n", +old_dentry->d_parent->d_name.name, old_dentry->d_name.name,old_dentry->d_count); + goto out_dput; + } + d_drop(old_dentry); + d_delete(old_dentry); +printk("umsdos_rename_f: cross-dir move, %s/%s dropped\n", +old_dentry->d_parent->d_name.name, old_dentry->d_name.name); + } + } new = umsdos_lookup_dentry(new_dentry->d_parent, new_info.fake.fname, new_info.fake.len, 1); @@ -481,27 +502,21 @@ ret); goto out_dput; } - /* - * Note! If the new short- and long-name dentries are - * aliases, the target name will be destroyed by the - * msdos-level rename. If in addition the old dentries - * _aren't_ aliased, we'll need the original new name - * for the final d_move, and so must make a copy here. - * - * Welcome to the mysteries of the dcache ... - */ - if (new == new_dentry) { +#ifdef UMSDOS_PARANOIA +if (new->d_inode != new_dentry->d_inode) +printk("umsdos_rename_f: new %s/%s, inode %p!=%p??\n", +new->d_parent->d_name.name, new->d_name.name, new->d_inode,new_dentry->d_inode); +#endif + /* short and long name dentries match? */ + if (new == new_dentry) dput(new); - if (old != old_dentry) { - /* make a copy of the target dentry */ - ret = -ENOMEM; - new_target = d_alloc(new_dentry->d_parent, - &new_dentry->d_name); - if (!new_target) - goto out_dput; - } - } +#ifdef UMSDOS_DEBUG_VERBOSE +printk("umsdos_rename_f: msdos_rename %s/%s(%ld) to %s/%s(%ld)\n", +old->d_parent->d_name.name, old->d_name.name, old->d_inode->i_ino, +new->d_parent->d_name.name, new->d_name.name, +new->d_inode ? new->d_inode->i_ino : 0); +#endif /* Do the msdos-level rename */ ret = msdos_rename (old_dir, old, new_dir, new); Printk(("umsdos_rename_f: now %s/%s, ret=%d\n", @@ -534,23 +549,31 @@ err); } - /* dput() the dentry if we haven't already */ -out_dput: - if (old_dentry != old) - dput(old); - if (ret) - goto out_unlock; /* * Check whether to update the dcache ... if both * old and new dentries match, it's already correct. - */ - if (new_dentry != new) { + * If the targets were aliases, the old short-name + * dentry has the original target name. + */ + if (old_dentry != old) { + if (!old_dentry->d_inode) { + struct inode *inode = old->d_inode; + inode->i_count++; + d_instantiate(old_dentry, inode); +printk("umsdos_rename_f: %s/%s gets new ino=%ld\n", +old_dentry->d_parent->d_name.name, old_dentry->d_name.name, inode->i_ino); + } + if (new_dentry == new) + new_dentry = old; + goto move_it; + } else if (new_dentry != new) { + move_it: + /* this will rehash the dentry ... */ d_move(old_dentry, new_dentry); - } else if (old_dentry != old) { - /* new dentry was destroyed ... */ - d_drop(new_dentry); - d_add(new_target, NULL); - d_move(old_dentry, new_target); + } + /* Check whether the old inode changed ... */ + if (old_dentry->d_inode != old_inode) { + umsdos_lookup_patch_new(old_dentry, &new_info); } /* @@ -559,8 +582,12 @@ */ umsdos_set_dirinfo_new(old_dentry, new_info.f_pos); + /* dput() the dentry if we haven't already */ +out_dput: + if (old_dentry != old) + dput(old); + out_unlock: - dput(new_target); dput(old_emd); umsdos_unlockcreate (old_dir); umsdos_unlockcreate (new_dir); @@ -585,6 +612,8 @@ * Let's go for simplicity... */ +extern struct inode_operations umsdos_symlink_inode_operations; + static int umsdos_symlink_x (struct inode *dir, struct dentry *dentry, const char *symname, int mode, char flags) { @@ -596,29 +625,28 @@ ret = umsdos_create_any (dir, dentry, mode, 0, flags); if (ret) { -printk("umsdos_symlink: create failed, ret=%d\n", ret); + printk(KERN_WARNING + "umsdos_symlink: create failed, ret=%d\n", ret); goto out; } fill_new_filp (&filp, dentry); len = strlen (symname); ret = umsdos_file_write_kmem_real (&filp, symname, len); - if (ret >= 0) { - if (ret != len) { - ret = -EIO; - printk (KERN_WARNING - "UMSDOS: Can't write symbolic link data\n"); - } else { - ret = 0; - } - } - if (ret != 0) { -printk("umsdos_symlink: write failed, unlinking\n"); - UMSDOS_unlink (dir, dentry); - } - + if (ret < 0) + goto out_unlink; + if (ret != len) + goto out_error; + ret = 0; out: return ret; + +out_error: + ret = -EIO; +out_unlink: + printk(KERN_WARNING "umsdos_symlink: write failed, unlinking\n"); + UMSDOS_unlink (dir, dentry); + goto out; } /* @@ -665,7 +693,15 @@ if (!buffer) goto out; - umsdos_lockcreate2 (dir, olddir); + /* + * Lock the link parent if it's not the same directory. + */ + ret = -EDEADLOCK; + if (olddir != dir) { + if (atomic_read(&olddir->i_sem.count) < 1) + goto out_free; + down(&olddir->i_sem); + } /* * Parse the name and get the visible directory entry. @@ -802,10 +838,7 @@ ret = umsdos_symlink_x (dir, dentry, path, S_IFREG | 0777,UMSDOS_HLINK); out_unlock: - umsdos_unlockcreate (olddir); - umsdos_unlockcreate (dir); - free_page(buffer); -out: + /* remain locked for the call to notify_change ... */ if (ret == 0) { struct iattr newattrs; @@ -819,8 +852,14 @@ olddentry->d_parent->d_name.name, olddentry->d_name.name, oldinode->i_ino, oldinode->i_nlink)); newattrs.ia_valid = 0; - ret = UMSDOS_notify_change (olddentry, &newattrs); + ret = umsdos_notify_change_locked(olddentry, &newattrs); } + if (olddir != dir) + up(&olddir->i_sem); + +out_free: + free_page(buffer); +out: Printk (("umsdos_link %d\n", ret)); return ret; } @@ -854,7 +893,6 @@ if (ret) goto out; - umsdos_lockcreate (dir); info.entry.mode = mode | S_IFDIR; info.entry.rdev = 0; info.entry.uid = current->fsuid; @@ -864,26 +902,36 @@ info.entry.nlink = 1; ret = umsdos_newentry (dentry->d_parent, &info); if (ret) - goto out_unlock; + goto out; /* lookup the short name dentry */ temp = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname, info.fake.len, 1); ret = PTR_ERR(temp); if (IS_ERR(temp)) - goto out_unlock; + goto out_remove; + + /* Keep the short name dentry anonymous */ + if (temp != dentry) + d_drop(temp); /* Make sure the short name doesn't exist */ ret = -EEXIST; if (temp->d_inode) { printk("umsdos_mkdir: short name %s/%s exists\n", dentry->d_parent->d_name.name, info.fake.fname); - goto out_remove; + goto out_remove_dput; } ret = msdos_mkdir (dir, temp, mode); if (ret) - goto out_remove; + goto out_remove_dput; + + /* + * Lock the inode to protect the EMD creation ... + */ + inode = temp->d_inode; + down(&inode->i_sem); /* * Note! The long and short name might be the same, @@ -892,11 +940,11 @@ if (dentry != temp) { if (dentry->d_inode) printk("umsdos_mkdir: dentry not negative!\n"); - inode = temp->d_inode; inode->i_count++; d_instantiate(dentry, inode); } - umsdos_lookup_patch_new(dentry, &info.entry, info.f_pos); + /* N.B. this should have an option to create the EMD ... */ + umsdos_lookup_patch_new(dentry, &info); /* * Create the EMD file, and set up the dir so it is @@ -907,22 +955,20 @@ err = umsdos_make_emd(dentry); umsdos_setup_dir(dentry); -out_dput: - /* kill off the short name dentry */ - if (temp != dentry) - d_drop(temp); + up(&inode->i_sem); dput(temp); -out_unlock: - umsdos_unlockcreate (dir); out: - Printk (("umsdos_mkdir %d\n", ret)); + Printk(("umsdos_mkdir: %s/%s, ret=%d\n", + dentry->d_parent->d_name.name, dentry->d_name.name, ret)); return ret; /* an error occurred ... remove EMD entry. */ +out_remove_dput: + dput(temp); out_remove: umsdos_delentry (dentry->d_parent, &info, 1); - goto out_dput; + goto out; } /* @@ -961,53 +1007,52 @@ if (ret) goto out; - umsdos_lockcreate (dir); ret = -EBUSY; - if (dentry->d_count > 1) { - shrink_dcache_parent(dentry); - if (dentry->d_count > 1) { -printk("umsdos_rmdir: %s/%s busy\n", -dentry->d_parent->d_name.name, dentry->d_name.name); - goto out_unlock; - } - } + shrink_dcache_parent(dentry); + if (dentry->d_count > 1) + goto out; /* check the sticky bit */ ret = -EPERM; if (is_sticky(dir, dentry->d_inode->i_uid)) { printk("umsdos_rmdir: %s/%s is sticky\n", dentry->d_parent->d_name.name, dentry->d_name.name); - goto out_unlock; + goto out; } + /* + * Lock the directory, then check whether it's empty. + */ + down(&dentry->d_inode->i_sem); + /* check whether the EMD is empty */ - empty = umsdos_isempty (dentry); ret = -ENOTEMPTY; - if (empty == 0) - goto out_unlock; + empty = umsdos_isempty (dentry); /* Have to remove the EMD file? */ if (empty == 1) { struct dentry *demd; Printk (("UMSDOS_rmdir: unlinking empty EMD err=%d", err)); - - ret = -ENOTEMPTY; - /* see if there's an EMD file ... */ demd = umsdos_get_emd_dentry(dentry); - if (IS_ERR(demd)) - goto out_unlock; - - err = msdos_unlink (dentry->d_inode, demd); + if (!IS_ERR(demd)) { + err = -ENOENT; + if (demd->d_inode) + err = msdos_unlink (dentry->d_inode, demd); #ifdef UMSDOS_PARANOIA if (err) printk("umsdos_rmdir: EMD %s/%s unlink failed, err=%d\n", demd->d_parent->d_name.name, demd->d_name.name, err); #endif - dput(demd); - if (err) - goto out_unlock; - } + dput(demd); + if (!err) + ret = 0; + } + } else if (empty == 2) + ret = 0; + up(&dentry->d_inode->i_sem); + if (ret) + goto out; umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info); /* Call findentry to complete the mangling */ @@ -1016,14 +1061,23 @@ info.fake.len, 1); ret = PTR_ERR(temp); if (IS_ERR(temp)) - goto out_unlock; + goto out; /* - * If the short name matches the dentry, dput() it now. + * If the short name is an alias, dput() it now; + * otherwise d_drop() it to keep it anonymous. */ - if (temp == dentry) { + if (temp == dentry) dput(temp); -Printk(("umsdos_rmdir: %s/%s, short matches long\n", -dentry->d_parent->d_name.name, dentry->d_name.name)); + else + d_drop(temp); + + /* Check again for a busy dentry */ + ret = -EBUSY; + shrink_dcache_parent(dentry); + if (dentry->d_count > 1) { +printk("umsdos_rmdir: %s/%s busy\n", +dentry->d_parent->d_name.name, dentry->d_name.name); + goto out_dput; } /* @@ -1043,15 +1097,11 @@ /* dput() temp if we didn't do it above */ out_dput: if (temp != dentry) { - d_drop(temp); dput(temp); if (!ret) d_delete (dentry); } -out_unlock: - umsdos_unlockcreate (dir); - out: Printk (("umsdos_rmdir %d\n", ret)); return ret; @@ -1196,6 +1246,10 @@ /* * If this was the last linked reference, delete it now. + * + * N.B. Deadlock problem? We should be holding the lock + * for the hardlink's parent, but another process might + * be holding that lock waiting for us to finish ... */ if (inode->i_nlink <= 1) { ret = UMSDOS_unlink (link->d_parent->d_inode, link); @@ -1208,7 +1262,7 @@ struct iattr newattrs; inode->i_nlink--; newattrs.ia_valid = 0; - ret = UMSDOS_notify_change (link, &newattrs); + ret = umsdos_notify_change_locked(link, &newattrs); } out_cleanup: @@ -1227,38 +1281,49 @@ int UMSDOS_rename (struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { + struct dentry *new_target; int ret; +#ifdef UMSDOS_DEBUG_VERBOSE +printk("umsdos_rename: enter, %s/%s(%ld) to %s/%s(%ld)\n", +old_dentry->d_parent->d_name.name, old_dentry->d_name.name, +old_dentry->d_inode->i_ino, +new_dentry->d_parent->d_name.name, new_dentry->d_name.name, +new_dentry->d_inode ? new_dentry->d_inode->i_ino : 0); +#endif ret = umsdos_nevercreat (new_dir, new_dentry, -EEXIST); if (ret) goto out; - ret = umsdos_rename_f(old_dir, old_dentry, new_dir, new_dentry, 0); - if (ret != -EEXIST) - goto out; - /* - * Something seems to be giving negative lookups when - * the file really exists ... track this down! + * If the target already exists, delete it first. */ - ret = -EIO; - if (!new_dentry->d_inode) { -printk("UMSDOS_rename: %s/%s negative, error EEXIST??\n", -new_dentry->d_parent->d_name.name, new_dentry->d_name.name); - d_drop(new_dentry); - goto out; + if (new_dentry->d_inode) { + if (S_ISDIR(new_dentry->d_inode->i_mode)) + ret = UMSDOS_rmdir (new_dir, new_dentry); + else + ret = UMSDOS_unlink (new_dir, new_dentry); + if (ret) + goto out; } - /* This is not terribly efficient but should work. */ - if (S_ISDIR(new_dentry->d_inode->i_mode)) - ret = UMSDOS_rmdir (new_dir, new_dentry); - else - ret = UMSDOS_unlink (new_dir, new_dentry); - if (ret) - goto out; - - /* this time the rename should work ... */ - ret = umsdos_rename_f(old_dir, old_dentry, new_dir, new_dentry, 0); + /* + * If we didn't get a negative dentry, make a copy and hash it. + */ + new_target = new_dentry; + if (new_dentry->d_inode) { +printk("umsdos_rename: %s/%s not negative, hash=%d\n", +new_dentry->d_parent->d_name.name, new_dentry->d_name.name, +!list_empty(&new_dentry->d_hash)); + ret = -ENOMEM; + new_target = d_alloc(new_dentry->d_parent, &new_dentry->d_name); + if (!new_target) + goto out; + d_add(new_target, NULL); + } + ret = umsdos_rename_f(old_dir, old_dentry, new_dir, new_target, 0); + if (new_target != new_dentry) + dput(new_target); out: return ret; diff -u --recursive --new-file v2.1.122/linux/fs/umsdos/rdir.c linux/fs/umsdos/rdir.c --- v2.1.122/linux/fs/umsdos/rdir.c Thu Sep 17 17:53:38 1998 +++ linux/fs/umsdos/rdir.c Fri Sep 25 16:30:07 1998 @@ -19,6 +19,7 @@ #include +extern struct dentry *saved_root; extern struct inode *pseudo_root; extern struct dentry_operations umsdos_dentry_operations; @@ -64,9 +65,7 @@ bufk.filldir = filldir; bufk.dirbuf = dirbuf; - bufk.real_root = pseudo_root && - dir->i_ino == UMSDOS_ROOT_INO && - dir->i_sb == pseudo_root->i_sb; + bufk.real_root = pseudo_root && (dir == saved_root->d_inode); return fat_readdir (filp, &bufk, rdir_filldir); } @@ -82,30 +81,41 @@ */ int umsdos_rlookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo) { - /* so locating "linux" will work */ - const char *name = dentry->d_name.name; - int len = dentry->d_name.len; - struct inode *inode; int ret; + /* N.B. this won't work ... lookups of `..' are done by VFS */ +#ifdef BROKEN_TO_BITS if (pseudo_root && len == 2 && name[0] == '.' && name[1] == '.' && - dir->i_ino == UMSDOS_ROOT_INO && dir->i_sb == pseudo_root->i_sb) { + dir == saved_root->d_inode) { printk (KERN_WARNING "umsdos_rlookup_x: we are at pseudo-root thingy?\n"); pseudo_root->i_count++; d_add(dentry, pseudo_root); ret = 0; goto out; } +#endif ret = msdos_lookup (dir, dentry); if (ret) { - printk(KERN_WARNING "umsdos_rlookup_x: lookup failed, ret=%d\n", - ret); + printk(KERN_WARNING + "umsdos_rlookup_x: %s/%s failed, ret=%d\n", + dentry->d_parent->d_name.name, dentry->d_name.name,ret); goto out; } - inode = dentry->d_inode; - if (inode) { - if (inode == pseudo_root && !nopseudo) { + if (dentry->d_inode) { + /* We must install the proper function table + * depending on whether this is an MS-DOS or + * a UMSDOS directory + */ +Printk ((KERN_DEBUG "umsdos_rlookup_x: setting up setup_dir_inode %lu...\n", +inode->i_ino)); + umsdos_patch_dentry_inode(dentry, 0); + + /* N.B. Won't work -- /linux dentry will already have + * an inode, so we'll never get called here. + */ +#ifdef BROKEN_TO_BITS + if (dentry->d_inode == pseudo_root && !nopseudo) { /* #Specification: pseudo root / DOS/linux * Even in the real root directory (c:\), the directory * /linux won't show @@ -114,20 +124,11 @@ /* make the dentry negative */ d_delete(dentry); } - else if (S_ISDIR (inode->i_mode)) { - /* We must place the proper function table - * depending on whether this is an MS-DOS or - * a UMSDOS directory - */ -Printk ((KERN_DEBUG "umsdos_rlookup_x: setting up setup_dir_inode %lu...\n", -inode->i_ino)); - umsdos_setup_dir(dentry); - } +#endif } out: /* always install our dentry ops ... */ dentry->d_op = &umsdos_dentry_operations; - PRINTK ((KERN_DEBUG "umsdos_rlookup_x: returning %d\n", ret)); return ret; } @@ -168,18 +169,18 @@ if (umsdos_is_pseudodos (dir, dentry)) goto out; - umsdos_lockcreate (dir); ret = -EBUSY; if (dentry->d_count > 1) { shrink_dcache_parent(dentry); if (dentry->d_count > 1) - goto out_unlock; + goto out; } ret = msdos_rmdir (dir, dentry); if (ret != -ENOTEMPTY) - goto out_unlock; + goto out; + down(&dentry->d_inode->i_sem); empty = umsdos_isempty (dentry); if (empty == 1) { struct dentry *demd; @@ -192,14 +193,14 @@ ret = msdos_unlink (dentry->d_inode, demd); dput(demd); } - if (ret) - goto out_unlock; } + up(&dentry->d_inode->i_sem); + if (ret) + goto out; + /* now retry the original ... */ ret = msdos_rmdir (dir, dentry); -out_unlock: - umsdos_unlockcreate (dir); out: return ret; } diff -u --recursive --new-file v2.1.122/linux/fs/umsdos/symlink.c linux/fs/umsdos/symlink.c --- v2.1.122/linux/fs/umsdos/symlink.c Thu Sep 17 17:53:38 1998 +++ linux/fs/umsdos/symlink.c Sat Sep 19 13:46:28 1998 @@ -64,7 +64,8 @@ /* this one mostly stolen from romfs :) */ static struct dentry *UMSDOS_followlink (struct dentry *dentry, - struct dentry *base) + struct dentry *base, + unsigned int follow) { struct inode *inode = dentry->d_inode; char *symname; @@ -91,7 +92,7 @@ } symname[len] = 0; - dentry = lookup_dentry (symname, base, 1); + dentry = lookup_dentry (symname, base, follow); kfree (symname); if (0) { diff -u --recursive --new-file v2.1.122/linux/include/linux/console.h linux/include/linux/console.h --- v2.1.122/linux/include/linux/console.h Sun Jul 26 11:57:19 1998 +++ linux/include/linux/console.h Thu Sep 17 09:35:03 1998 @@ -53,15 +53,11 @@ extern struct consw prom_con; /* SPARC PROM console */ void take_over_console(struct consw *sw, int first, int last, int deflt); - -/* flag bits */ -#define CON_INITED (1) +void give_up_console(struct consw *sw); /* scroll */ #define SM_UP (1) #define SM_DOWN (2) -#define SM_LEFT (3) -#define SM_RIGHT (4) /* cursor */ #define CM_DRAW (1) diff -u --recursive --new-file v2.1.122/linux/include/linux/console_struct.h linux/include/linux/console_struct.h --- v2.1.122/linux/include/linux/console_struct.h Thu Aug 6 14:06:34 1998 +++ linux/include/linux/console_struct.h Thu Sep 17 09:35:04 1998 @@ -19,7 +19,6 @@ struct consw *vc_sw; unsigned short *vc_screenbuf; /* In-memory character/attribute buffer */ unsigned int vc_screenbuf_size; - unsigned short vc_video_erase_char; /* Background erase character */ unsigned char vc_attr; /* Current attributes */ unsigned char vc_def_color; /* Default colors */ unsigned char vc_color; /* Foreground & background */ @@ -28,6 +27,8 @@ unsigned char vc_halfcolor; /* Color for half intensity mode */ unsigned short vc_complement_mask; /* [#] Xor mask for mouse pointer */ unsigned short vc_hi_font_mask; /* [#] Attribute set for upper 256 chars of font or 0 if not supported */ + unsigned short vc_video_erase_char; /* Background erase character */ + unsigned short vc_s_complement_mask; /* Saved mouse pointer mask */ unsigned int vc_x, vc_y; /* Cursor position */ unsigned int vc_top, vc_bottom; /* Scrolling region */ unsigned int vc_state; /* Escape sequence parser state */ @@ -104,3 +105,5 @@ #define CUR_SWMASK 0xfff0 #define CUR_DEFAULT CUR_UNDERLINE + +#define CON_IS_VISIBLE(conp) (*conp->vc_display_fg == conp) diff -u --recursive --new-file v2.1.122/linux/include/linux/dcache.h linux/include/linux/dcache.h --- v2.1.122/linux/include/linux/dcache.h Tue Aug 18 22:02:07 1998 +++ linux/include/linux/dcache.h Sat Sep 19 14:27:29 1998 @@ -27,7 +27,7 @@ #define init_name_hash() 0 /* partial hash update function. Assume roughly 4 bits per character */ -static __inline__ unsigned long partial_name_hash(unsigned char c, unsigned long prevhash) +static __inline__ unsigned long partial_name_hash(unsigned long c, unsigned long prevhash) { prevhash = (prevhash << 4) | (prevhash >> (8*sizeof(unsigned long)-4)); return prevhash ^ c; diff -u --recursive --new-file v2.1.122/linux/include/linux/ext2_fs.h linux/include/linux/ext2_fs.h --- v2.1.122/linux/include/linux/ext2_fs.h Fri Jul 31 17:05:52 1998 +++ linux/include/linux/ext2_fs.h Fri Sep 25 23:02:43 1998 @@ -520,6 +520,7 @@ extern int ext2_permission (struct inode *, int); /* balloc.c */ +extern int ext2_group_sparse(int group); extern int ext2_new_block (const struct inode *, unsigned long, __u32 *, __u32 *, int *); extern void ext2_free_blocks (const struct inode *, unsigned long, diff -u --recursive --new-file v2.1.122/linux/include/linux/fs.h linux/include/linux/fs.h --- v2.1.122/linux/include/linux/fs.h Sat Sep 5 16:46:41 1998 +++ linux/include/linux/fs.h Fri Sep 25 16:42:27 1998 @@ -348,6 +348,7 @@ unsigned long i_version; unsigned long i_nrpages; struct semaphore i_sem; + struct semaphore i_atomic_write; struct inode_operations *i_op; struct super_block *i_sb; struct wait_queue *i_wait; @@ -622,7 +623,7 @@ int (*rename) (struct inode *, struct dentry *, struct inode *, struct dentry *); int (*readlink) (struct dentry *, char *,int); - struct dentry * (*follow_link) (struct dentry *, struct dentry *); + struct dentry * (*follow_link) (struct dentry *, struct dentry *, unsigned int); int (*readpage) (struct file *, struct page *); int (*writepage) (struct file *, struct page *); int (*bmap) (struct inode *,int); @@ -783,8 +784,8 @@ #define PTR_ERR(ptr) ((long)(ptr)) #define IS_ERR(ptr) ((unsigned long)(ptr) > (unsigned long)(-1000)) -extern struct dentry * lookup_dentry(const char *, struct dentry *, int); -extern struct dentry * __namei(const char *, int); +extern struct dentry * lookup_dentry(const char *, struct dentry *, unsigned int); +extern struct dentry * __namei(const char *, unsigned int); #define namei(pathname) __namei(pathname, 1) #define lnamei(pathname) __namei(pathname, 0) diff -u --recursive --new-file v2.1.122/linux/include/linux/nbd.h linux/include/linux/nbd.h --- v2.1.122/linux/include/linux/nbd.h Sat Sep 5 16:46:41 1998 +++ linux/include/linux/nbd.h Thu Sep 17 09:16:28 1998 @@ -35,7 +35,6 @@ } #define MAX_NBD 128 -#endif struct nbd_device { int refcnt; @@ -51,6 +50,7 @@ struct request *tail; struct semaphore queue_lock; }; +#endif /* This now IS in some kind of include file... */ diff -u --recursive --new-file v2.1.122/linux/include/linux/quota.h linux/include/linux/quota.h --- v2.1.122/linux/include/linux/quota.h Fri May 8 23:14:56 1998 +++ linux/include/linux/quota.h Fri Sep 25 16:24:56 1998 @@ -165,19 +165,23 @@ #define DQ_FAKE 0x40 /* no limits only usage */ struct dquot { + struct dquot *dq_next; /* Pointer to next dquot */ + struct dquot **dq_pprev; + struct list_head dq_free; /* free list element */ + struct dquot *dq_hash_next; /* Pointer to next in dquot_hash */ + struct dquot **dq_hash_pprev; /* Pointer to previous in dquot_hash */ + struct wait_queue *dq_wait; /* Pointer to waitqueue */ + int dq_count; /* Reference count */ + + /* fields after this point are cleared when invalidating */ + struct vfsmount *dq_mnt; /* VFS_mount_point this applies to */ unsigned int dq_id; /* ID this applies to (uid, gid) */ - short dq_type; /* Type of quota */ kdev_t dq_dev; /* Device this applies to */ + short dq_type; /* Type of quota */ short dq_flags; /* See DQ_* */ - short dq_count; /* Reference count */ - unsigned long dq_referenced; /* Number of times this dquot was referenced during its lifetime */ - struct vfsmount *dq_mnt; /* VFS_mount_point this applies to */ + unsigned long dq_referenced; /* Number of times this dquot was + referenced during its lifetime */ struct dqblk dq_dqb; /* Diskquota usage */ - struct wait_queue *dq_wait; /* Pointer to waitqueue */ - struct dquot *dq_next; /* Pointer to next dquot */ - struct dquot *dq_hash_next; /* Pointer to next in dquot_hash */ - struct dquot **dq_hash_pprev; /* Pointer to previous in dquot_hash */ - struct dquot **dq_pprev; }; #define NODQUOT (struct dquot *)NULL diff -u --recursive --new-file v2.1.122/linux/include/linux/selection.h linux/include/linux/selection.h --- v2.1.122/linux/include/linux/selection.h Fri Jul 31 17:07:03 1998 +++ linux/include/linux/selection.h Fri Sep 25 16:39:31 1998 @@ -21,7 +21,6 @@ #define video_num_columns (vc_cons[currcons].d->vc_cols) #define video_num_lines (vc_cons[currcons].d->vc_rows) #define video_size_row (vc_cons[currcons].d->vc_size_row) -#define video_screen_size (vc_cons[currcons].d->vc_screenbuf_size) #define can_do_color (vc_cons[currcons].d->vc_can_do_color) extern int console_blanked; @@ -31,7 +30,6 @@ extern int default_grn[]; extern int default_blu[]; -extern void do_unblank_screen(void); extern unsigned short *screen_pos(int currcons, int w_offset, int viewed); extern u16 screen_glyph(int currcons, int offset); extern void complement_pos(int currcons, int offset); diff -u --recursive --new-file v2.1.122/linux/include/linux/socket.h linux/include/linux/socket.h --- v2.1.122/linux/include/linux/socket.h Sat Sep 5 16:46:41 1998 +++ linux/include/linux/socket.h Mon Sep 21 15:38:39 1998 @@ -262,6 +262,7 @@ extern int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode); extern int memcpy_toiovec(struct iovec *v, unsigned char *kdata, int len); +extern void memcpy_tokerneliovec(struct iovec *iov, unsigned char *kdata, int len); extern int move_addr_to_user(void *kaddr, int klen, void *uaddr, int *ulen); extern int move_addr_to_kernel(void *uaddr, int ulen, void *kaddr); extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data); diff -u --recursive --new-file v2.1.122/linux/include/linux/sunrpc/auth.h linux/include/linux/sunrpc/auth.h --- v2.1.122/linux/include/linux/sunrpc/auth.h Fri Jul 31 17:09:54 1998 +++ linux/include/linux/sunrpc/auth.h Sat Sep 26 10:37:31 1998 @@ -14,6 +14,8 @@ #include #include +/* size of the nodename buffer */ +#define UNX_MAXNODENAME 32 /* * Client user credentials diff -u --recursive --new-file v2.1.122/linux/include/linux/sunrpc/clnt.h linux/include/linux/sunrpc/clnt.h --- v2.1.122/linux/include/linux/sunrpc/clnt.h Thu Aug 20 17:05:19 1998 +++ linux/include/linux/sunrpc/clnt.h Sat Sep 26 10:37:31 1998 @@ -52,6 +52,9 @@ struct rpc_portmap cl_pmap; /* port mapping */ struct rpc_wait_queue cl_bindwait; /* waiting on getport() */ + + int cl_nodelen; /* nodename length */ + char cl_nodename[UNX_MAXNODENAME]; }; #define cl_timeout cl_xprt->timeout #define cl_prog cl_pmap.pm_prog diff -u --recursive --new-file v2.1.122/linux/include/linux/tcp.h linux/include/linux/tcp.h --- v2.1.122/linux/include/linux/tcp.h Fri Jul 31 17:07:27 1998 +++ linux/include/linux/tcp.h Fri Sep 25 16:39:28 1998 @@ -71,7 +71,7 @@ }; #define TCP_STATE_MASK 0xF -#define TCP_ACTION_FIN 1 << 7 +#define TCP_ACTION_FIN (1 << 7) enum { TCPF_ESTABLISHED = (1 << 1), diff -u --recursive --new-file v2.1.122/linux/include/linux/tty.h linux/include/linux/tty.h --- v2.1.122/linux/include/linux/tty.h Thu Aug 6 14:06:34 1998 +++ linux/include/linux/tty.h Fri Sep 25 16:42:30 1998 @@ -9,7 +9,7 @@ * These constants are also useful for user-level apps (e.g., VC * resizing). */ -#define MIN_NR_CONSOLES 1 /* must be at least 1 */ +#define MIN_NR_CONSOLES 1 /* must be at least 1 */ #define MAX_NR_CONSOLES 63 /* serial lines start at 64 */ #define MAX_NR_USER_CONSOLES 63 /* must be root to allocate above this */ /* Note: the ioctl VT_GETSTATE does not work for @@ -87,7 +87,10 @@ unsigned char blue_pos; /* 0x2b */ unsigned char rsvd_size; /* 0x2c */ unsigned char rsvd_pos; /* 0x2d */ - /* 0x2e -- 0x3f reserved for future expansion */ + unsigned short vesapm_seg; /* 0x2e */ + unsigned short vesapm_off; /* 0x30 */ + unsigned short pages; /* 0x32 */ + /* 0x34 -- 0x3f reserved for future expansion */ }; extern struct screen_info screen_info; @@ -389,10 +392,6 @@ /* pcxx.c */ extern int pcxe_open(struct tty_struct *tty, struct file *filp); - -/* console.c */ - -extern void update_screen(int new_console); /* printk.c */ diff -u --recursive --new-file v2.1.122/linux/include/linux/umsdos_fs.p linux/include/linux/umsdos_fs.p --- v2.1.122/linux/include/linux/umsdos_fs.p Thu Sep 17 17:53:38 1998 +++ linux/include/linux/umsdos_fs.p Fri Sep 25 16:30:07 1998 @@ -2,31 +2,14 @@ void check_page_tables (void); /* dir.c 22/06/95 00.22.12 */ -int compat_msdos_create(struct inode *dir, - const char *name, - int len, - int mode, - struct inode **inode); int dummy_dir_read ( struct file *filp, char *buf, size_t size, loff_t *count); char * umsdos_d_path(struct dentry *, char *, int); -void umsdos_lookup_patch_new(struct dentry *, struct umsdos_dirent *, off_t); -void umsdos_lookup_patch (struct inode *dir, - struct inode *inode, - struct umsdos_dirent *entry, - off_t emd_pos); -int umsdos_dentry_to_entry (struct dentry *, struct umsdos_dirent *); -int umsdos_inode2entry (struct inode *dir, - struct inode *inode, - struct umsdos_dirent *entry); -int umsdos_locate_path (struct inode *inode, char *path); +void umsdos_lookup_patch_new(struct dentry *, struct umsdos_info *); int umsdos_is_pseudodos (struct inode *dir, struct dentry *dentry); -int umsdos_lookup_x ( - struct inode *dir, - struct dentry *dentry, - int nopseudo); +int umsdos_lookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo); int UMSDOS_lookup(struct inode *, struct dentry *); struct dentry *umsdos_lookup_dentry(struct dentry *, char *, int, int); @@ -52,7 +35,6 @@ struct dentry *umsdos_get_emd_dentry(struct dentry *); int umsdos_have_emd(struct dentry *); int umsdos_make_emd(struct dentry *); -struct inode *umsdos_emd_dir_lookup (struct inode *dir, int creat); int umsdos_emd_dir_readentry (struct file *, struct umsdos_dirent *); int umsdos_newentry (struct dentry *, struct umsdos_info *); int umsdos_newhidden (struct dentry *, struct umsdos_info *); @@ -63,32 +45,20 @@ /* file.c 25/01/95 02.25.38 */ /* inode.c 12/06/95 09.49.40 */ -inline struct dentry *geti_dentry (struct inode *inode); -void checkd_inode (struct inode *inode); -void check_inode (struct inode *inode); -void check_dentry (struct dentry *dentry); -void check_dentry_path (struct dentry *dentry, const char *desc); void fill_new_filp (struct file *filp, struct dentry *dentry); -struct dentry *creat_dentry (const char *name, - const int len, - struct inode *inode, - struct dentry *parent); void UMSDOS_read_inode (struct inode *); void UMSDOS_write_inode (struct inode *); int UMSDOS_notify_change (struct dentry *, struct iattr *attr); +int umsdos_notify_change_locked(struct dentry *, struct iattr *attr); void UMSDOS_put_inode (struct inode *); int UMSDOS_statfs (struct super_block *, struct statfs *, int); struct super_block *UMSDOS_read_super (struct super_block *, void *, int); void UMSDOS_put_super (struct super_block *); -int umsdos_real_lookup(struct inode *, struct dentry *); void umsdos_setup_dir(struct dentry *); -void umsdos_setup_dir_inode (struct inode *inode); void umsdos_set_dirinfo_new(struct dentry *, off_t); -void umsdos_set_dirinfo (struct inode *, struct inode *, off_t); int umsdos_isinit (struct inode *inode); void umsdos_patch_dentry_inode (struct dentry *, off_t); -void umsdos_patch_inode (struct inode *, struct inode *, off_t); int umsdos_get_dirowner (struct inode *inode, struct inode **result); /* ioctl.c 22/06/95 00.22.08 */ @@ -96,6 +66,7 @@ struct file *filp, unsigned int cmd, unsigned long data); + /* mangle.c 25/01/95 02.25.38 */ void umsdos_manglename (struct umsdos_info *info); int umsdos_evalrecsize (int len); @@ -135,9 +106,13 @@ struct dentry *new_dentry); /* rdir.c 22/03/95 03.31.42 */ -int umsdos_rlookup_x (struct inode *dir, - struct dentry *dentry, - int nopseudo); -int UMSDOS_rlookup (struct inode *dir, - struct dentry *dentry); +int umsdos_rlookup_x (struct inode *dir, struct dentry *dentry, int nopseudo); +int UMSDOS_rlookup (struct inode *dir, struct dentry *dentry); + /* symlink.c 23/01/95 03.38.30 */ + +/* check.c */ +void checkd_inode (struct inode *inode); +void check_inode (struct inode *inode); +void check_dentry (struct dentry *dentry); +void check_dentry_path (struct dentry *dentry, const char *desc); diff -u --recursive --new-file v2.1.122/linux/include/linux/umsdos_fs_i.h linux/include/linux/umsdos_fs_i.h --- v2.1.122/linux/include/linux/umsdos_fs_i.h Fri Jul 31 17:05:52 1998 +++ linux/include/linux/umsdos_fs_i.h Fri Sep 25 16:30:07 1998 @@ -62,12 +62,14 @@ struct msdos_inode_info msdos_info; struct pipe_inode_info pipe_info; struct dir_locking_info dir_info; - } u; /* Simply a filler, never referenced by fs/umsdos/... */ - unsigned long i_dir_owner; /* Inode of the dir which hold this entry */ - unsigned long i_emd_owner; /* Inode of the EMD file of i_dir_owner */ + } u; + int i_patched; /* Inode has been patched */ + int i_is_hlink; /* Resolved hardlink inode? */ + unsigned long i_emd_owner; /* Is this the EMD file inode? */ off_t pos; /* Entry offset in the emd_owner file */ - /* The rest is used only if this inode describe a directory */ - unsigned long i_emd_dir; /* Inode of the EMD file of this inode */ + /* The rest is used only if this inode describes a directory */ + struct dentry *i_emd_dentry; /* EMD dentry for this directory */ + unsigned long i_emd_dir; /* Inode of the EMD file */ }; #endif diff -u --recursive --new-file v2.1.122/linux/include/linux/vt_buffer.h linux/include/linux/vt_buffer.h --- v2.1.122/linux/include/linux/vt_buffer.h Fri Jul 31 17:07:03 1998 +++ linux/include/linux/vt_buffer.h Fri Sep 25 16:39:26 1998 @@ -16,9 +16,6 @@ #include #ifdef CONFIG_VGA_CONSOLE -#if !defined(CONFIG_FB) && !defined(CONFIG_FB_MODULE) -#define VT_BUF_VRAM_ONLY -#endif #include #endif diff -u --recursive --new-file v2.1.122/linux/include/linux/vt_kern.h linux/include/linux/vt_kern.h --- v2.1.122/linux/include/linux/vt_kern.h Fri Jul 31 17:07:03 1998 +++ linux/include/linux/vt_kern.h Fri Sep 25 16:39:26 1998 @@ -35,27 +35,29 @@ /* console.c */ struct console_font_op; +struct consw; -int vc_allocate(unsigned int console, int init); +int vc_allocate(unsigned int console); int vc_cons_allocated(unsigned int console); int vc_resize(unsigned int lines, unsigned int cols, unsigned int first, unsigned int last); #define vc_resize_all(l, c) vc_resize(l, c, 0, MAX_NR_CONSOLES-1) #define vc_resize_con(l, c, x) vc_resize(l, c, x, x) void vc_disallocate(unsigned int console); -void poke_blanked_console(void); -void set_vesa_blanking(unsigned long arg); -void vesa_blank(void); -void vesa_powerdown(void); void reset_palette(int currcons); -void set_palette(void); -void do_blank_screen(int nopowersave); +void set_palette(int currcons); +void do_blank_screen(int gfx_mode); +void unblank_screen(void); +void poke_blanked_console(void); int con_font_op(int currcons, struct console_font_op *op); int con_set_cmap(unsigned char *cmap); int con_get_cmap(unsigned char *cmap); void scrollback(int); void scrollfront(int); void update_region(int currcons, unsigned long start, int count); +void redraw_screen(int new_console, int is_switch); +#define update_screen(x) redraw_screen(x, 0) +#define switch_screen(x) redraw_screen(x, 1) struct tty_struct; int tioclinux(struct tty_struct *tty, unsigned long arg); @@ -75,6 +77,7 @@ int con_set_default_unimap(int currcons); void con_free_unimap(int currcons); void con_protect_unimap(int currcons, int rdonly); +int con_copy_unimap(int dstcons, int srccons); /* vt.c */ diff -u --recursive --new-file v2.1.122/linux/init/main.c linux/init/main.c --- v2.1.122/linux/init/main.c Thu Sep 17 17:53:39 1998 +++ linux/init/main.c Mon Sep 21 13:35:32 1998 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -77,7 +78,7 @@ extern void sock_init(void); extern void uidcache_init(void); extern void mca_init(void); -extern long sbus_init(long, long); +extern long sbus_init(void); extern long powermac_init(unsigned long, unsigned long); extern void sysctl_init(void); extern void filescache_init(void); @@ -1115,15 +1116,47 @@ check_bugs(); printk("POSIX conformance testing by UNIFIX\n"); + /* + * We count on the initial thread going ok + * Like idlers init is an unlocked kernel thread, which will + * make syscalls (and thus be locked). + */ smp_init(); + kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + cpu_idle(NULL); +} - /* - * Ok, the machine is now initialized. None of the devices - * have been touched yet, but the CPU subsystem is up and - * running, and memory management works. - * - * Now we can finally start doing some real work.. - */ +#ifdef CONFIG_BLK_DEV_INITRD +static int do_linuxrc(void * shell) +{ + static char *argv[] = { "linuxrc", NULL, }; + + close(0);close(1);close(2); + setsid(); + (void) open("/dev/console",O_RDWR,0); + (void) dup(0); + (void) dup(0); + return execve(shell, argv, envp_init); +} + +static void __init no_initrd(char *s,int *ints) +{ + mount_initrd = 0; +} +#endif + +/* + * Ok, the machine is now initialized. None of the devices + * have been touched yet, but the CPU subsystem is up and + * running, and memory and process management works. + * + * Now we can finally start doing some real work.. + */ +static void __init do_basic_setup(void) +{ +#ifdef CONFIG_BLK_DEV_INITRD + int real_root_mountflags; +#endif #if defined(CONFIG_MTRR) /* Do this after SMP initialization */ /* @@ -1161,49 +1194,6 @@ ecard_init(); #endif - /* - * We count on the initial thread going ok - * Like idlers init is an unlocked kernel thread, which will - * make syscalls (and thus be locked). - */ - kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); -/* - * task[0] is meant to be used as an "idle" task: it may not sleep, but - * it might do some general things like count free pages or it could be - * used to implement a reasonable LRU algorithm for the paging routines: - * anything that can be useful, but shouldn't take time from the real - * processes. - * - * Right now task[0] just does an infinite idle loop. - */ - cpu_idle(NULL); -} - -#ifdef CONFIG_BLK_DEV_INITRD -static int do_linuxrc(void * shell) -{ - static char *argv[] = { "linuxrc", NULL, }; - - close(0);close(1);close(2); - setsid(); - (void) open("/dev/console",O_RDWR,0); - (void) dup(0); - (void) dup(0); - return execve(shell, argv, envp_init); -} - -static void __init no_initrd(char *s,int *ints) -{ - mount_initrd = 0; -} -#endif - -static void __init do_basic_setup(void) -{ -#ifdef CONFIG_BLK_DEV_INITRD - int real_root_mountflags; -#endif - /* Networking initialization needs a process context */ sock_init(); @@ -1222,6 +1212,7 @@ #endif #ifdef CONFIG_BLK_DEV_INITRD + real_root_dev = ROOT_DEV; real_root_mountflags = root_mountflags; if (initrd_start && mount_initrd) root_mountflags &= ~MS_RDONLY; @@ -1278,6 +1269,7 @@ static int init(void * unused) { + lock_kernel(); do_basic_setup(); /* @@ -1286,6 +1278,7 @@ * initmem segments and start the user-mode stuff.. */ free_initmem(); + unlock_kernel(); if (open("/dev/console", O_RDWR, 0) < 0) printk("Warning: unable to open an initial console.\n"); diff -u --recursive --new-file v2.1.122/linux/kernel/exit.c linux/kernel/exit.c --- v2.1.122/linux/kernel/exit.c Thu Sep 17 17:53:39 1998 +++ linux/kernel/exit.c Sat Sep 19 10:43:51 1998 @@ -415,15 +415,6 @@ struct wait_queue wait = { current, NULL }; struct task_struct *p; - if (stat_addr) { - if(verify_area(VERIFY_WRITE, stat_addr, sizeof(*stat_addr))) - return -EFAULT; - } - if (ru) { - if(verify_area(VERIFY_WRITE, ru, sizeof(*ru))) - return -EFAULT; - } - if (options & ~(WNOHANG|WUNTRACED|__WCLONE)) return -EINVAL; @@ -453,21 +444,23 @@ if (!(options & WUNTRACED) && !(p->flags & PF_PTRACED)) continue; read_unlock(&tasklist_lock); - if (ru != NULL) - getrusage(p, RUSAGE_BOTH, ru); - if (stat_addr) - __put_user((p->exit_code << 8) | 0x7f, stat_addr); - p->exit_code = 0; - retval = p->pid; + retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0; + if (!retval && stat_addr) + retval = put_user((p->exit_code << 8) | 0x7f, stat_addr); + if (!retval) { + p->exit_code = 0; + retval = p->pid; + } goto end_wait4; case TASK_ZOMBIE: current->times.tms_cutime += p->times.tms_utime + p->times.tms_cutime; current->times.tms_cstime += p->times.tms_stime + p->times.tms_cstime; read_unlock(&tasklist_lock); - if (ru != NULL) - getrusage(p, RUSAGE_BOTH, ru); - if (stat_addr) - __put_user(p->exit_code, stat_addr); + retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0; + if (!retval && stat_addr) + retval = put_user(p->exit_code, stat_addr); + if (retval) + goto end_wait4; retval = p->pid; if (p->p_opptr != p->p_pptr) { write_lock_irq(&tasklist_lock); diff -u --recursive --new-file v2.1.122/linux/net/core/iovec.c linux/net/core/iovec.c --- v2.1.122/linux/net/core/iovec.c Sat Sep 5 16:46:42 1998 +++ linux/net/core/iovec.c Mon Sep 21 14:19:00 1998 @@ -95,6 +95,30 @@ } /* + * In kernel copy to iovec. Returns -EFAULT on error. + * + * Note: this modifies the original iovec. + */ + +void memcpy_tokerneliovec(struct iovec *iov, unsigned char *kdata, int len) +{ + while(len>0) + { + if(iov->iov_len) + { + int copy = min(iov->iov_len, len); + memcpy(iov->iov_base, kdata, copy); + kdata+=copy; + len-=copy; + iov->iov_len-=copy; + iov->iov_base+=copy; + } + iov++; + } +} + + +/* * Copy iovec to kernel. Returns -EFAULT on error. * * Note: this modifies the original iovec. diff -u --recursive --new-file v2.1.122/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c --- v2.1.122/linux/net/ipv4/tcp.c Thu Sep 17 17:53:39 1998 +++ linux/net/ipv4/tcp.c Fri Sep 25 10:57:06 1998 @@ -598,9 +598,9 @@ sk->urginline || !tp->urg_data)) mask |= POLLIN | POLLRDNORM; - /* Always wake the user up when an error occurred */ - if (sock_wspace(sk) >= tcp_min_write_space(sk, tp) || sk->err) + if (sock_wspace(sk) >= tcp_min_write_space(sk, tp)) mask |= POLLOUT | POLLWRNORM; + if (tp->urg_data & URG_VALID) mask |= POLLPRI; } @@ -1458,7 +1458,8 @@ * reader process may not have drained the data yet! */ while((skb=__skb_dequeue(&sk->receive_queue))!=NULL) { - data_was_unread++; + u32 len = TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq - skb->h.th->fin; + data_was_unread += len; kfree_skb(skb); } diff -u --recursive --new-file v2.1.122/linux/net/netsyms.c linux/net/netsyms.c --- v2.1.122/linux/net/netsyms.c Thu Sep 17 17:53:40 1998 +++ linux/net/netsyms.c Mon Sep 21 15:38:39 1998 @@ -93,6 +93,7 @@ /* Socket layer support routines */ EXPORT_SYMBOL(memcpy_fromiovec); +EXPORT_SYMBOL(memcpy_tokerneliovec); EXPORT_SYMBOL(sock_create); EXPORT_SYMBOL(sock_alloc); EXPORT_SYMBOL(sock_release); diff -u --recursive --new-file v2.1.122/linux/net/sunrpc/auth_unix.c linux/net/sunrpc/auth_unix.c --- v2.1.122/linux/net/sunrpc/auth_unix.c Tue Aug 18 22:02:08 1998 +++ linux/net/sunrpc/auth_unix.c Sat Sep 26 10:37:31 1998 @@ -10,7 +10,6 @@ #include #include #include -#include #include #include @@ -28,13 +27,7 @@ #define UNX_CRED_EXPIRE (60 * HZ) -#ifndef DONT_FILLIN_HOSTNAME -/* # define UNX_MAXNODENAME (sizeof(system_utsname.nodename)-1) */ -# define UNX_MAXNODENAME 32 -# define UNX_WRITESLACK (21 + (UNX_MAXNODENAME >> 2)) -#else -# define UNX_WRITESLACK 20 -#endif +#define UNX_WRITESLACK (21 + (UNX_MAXNODENAME >> 2)) #ifdef RPC_DEBUG # define RPCDBG_FACILITY RPCDBG_AUTH @@ -170,6 +163,7 @@ static u32 * unx_marshal(struct rpc_task *task, u32 *p, int ruid) { + struct rpc_clnt *clnt = task->tk_client; struct unx_cred *cred = (struct unx_cred *) task->tk_cred; u32 *base, *hold; int i, n; @@ -177,20 +171,15 @@ *p++ = htonl(RPC_AUTH_UNIX); base = p++; *p++ = htonl(jiffies/HZ); -#ifndef DONT_FILLIN_HOSTNAME + /* - * Problem: The UTS name could change under us. We can't lock - * here to handle this. On the other hand we can't really - * go building a bad RPC! + * Copy the UTS nodename captured when the client was created. */ - if ((n = strlen((char *) system_utsname.nodename)) > UNX_MAXNODENAME) - n = UNX_MAXNODENAME; + n = clnt->cl_nodelen; *p++ = htonl(n); - memcpy(p, system_utsname.nodename, n); + memcpy(p, clnt->cl_nodename, n); p += (n + 3) >> 2; -#else - *p++ = 0; -#endif + if (ruid) { *p++ = htonl((u32) cred->uc_uid); *p++ = htonl((u32) cred->uc_gid); diff -u --recursive --new-file v2.1.122/linux/net/sunrpc/clnt.c linux/net/sunrpc/clnt.c --- v2.1.122/linux/net/sunrpc/clnt.c Wed Sep 9 14:51:13 1998 +++ linux/net/sunrpc/clnt.c Sat Sep 26 10:37:31 1998 @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -101,6 +102,12 @@ if (!rpcauth_create(flavor, clnt)) goto out_no_auth; + + /* save the nodename */ + clnt->cl_nodelen = strlen(system_utsname.nodename); + if (clnt->cl_nodelen > UNX_MAXNODENAME) + clnt->cl_nodelen = UNX_MAXNODENAME; + memcpy(clnt->cl_nodename, system_utsname.nodename, clnt->cl_nodelen); out: return clnt; diff -u --recursive --new-file v2.1.122/linux/net/sunrpc/xprt.c linux/net/sunrpc/xprt.c --- v2.1.122/linux/net/sunrpc/xprt.c Wed Aug 26 11:37:45 1998 +++ linux/net/sunrpc/xprt.c Mon Sep 21 15:49:13 1998 @@ -573,7 +573,6 @@ struct rpc_rqst *rovr; struct sk_buff *skb; struct iovec iov[MAX_IOVEC]; - mm_segment_t oldfs; int err, repsize, copied; dprintk("RPC: udp_data_ready...\n"); @@ -603,9 +602,8 @@ /* Okay, we have it. Copy datagram... */ memcpy(iov, rovr->rq_rvec, rovr->rq_rnr * sizeof(iov[0])); - oldfs = get_fs(); set_fs(get_ds()); - skb_copy_datagram_iovec(skb, 8, iov, copied); - set_fs(oldfs); + /* This needs to stay tied with the usermode skb_copy_dagram... */ + memcpy_tokerneliovec(iov, skb->data+8, copied); xprt_complete_rqst(xprt, rovr, copied);