Commit d13a7654 authored by Linus Torvalds's avatar Linus Torvalds

Import 2.1.123pre3

parent 36800b1c
...@@ -331,13 +331,7 @@ IP FIREWALL ...@@ -331,13 +331,7 @@ IP FIREWALL
P: Paul Russell P: Paul Russell
M: Paul.Russell@rustcorp.com.au M: Paul.Russell@rustcorp.com.au
W: http://www.adelaide.net.au/~rustcorp/ipfwchains/ipfwchains.html W: http://www.adelaide.net.au/~rustcorp/ipfwchains/ipfwchains.html
S: Maintained S: Supported
IP FIREWALL
P: Paul Russell
M: Paul.Russell@rustcorp.com.au
W: http://www.adelaide.net.au/~rustcorp/ipfwchains/ipfwchains.html
S: Maintained
IPX/SPX NETWORK LAYER IPX/SPX NETWORK LAYER
P: Jay Schulist P: Jay Schulist
......
/* /*
* bios32.c - Low-Level PCI Access * 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 * Copyright 1993, 1994 Drew Eckhardt
* Visionary Computing * Visionary Computing
...@@ -170,6 +170,7 @@ PCI_STUB(write, dword, u32) ...@@ -170,6 +170,7 @@ PCI_STUB(write, dword, u32)
#define PCI_PROBE_CONF2 4 #define PCI_PROBE_CONF2 4
#define PCI_NO_SORT 0x100 #define PCI_NO_SORT 0x100
#define PCI_BIOS_SORT 0x200 #define PCI_BIOS_SORT 0x200
#define PCI_NO_CHECKS 0x400
static unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2; static unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2;
...@@ -343,14 +344,21 @@ static struct pci_access pci_direct_conf2 = { ...@@ -343,14 +344,21 @@ static struct pci_access pci_direct_conf2 = {
* whether bus 00 contains a host bridge (this is similar to checking * whether bus 00 contains a host bridge (this is similar to checking
* techniques used in XFree86, but ours should be more reliable since we * 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). * 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)) __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++) for(dfn=0; dfn < 0x100; dfn++)
if (!a->read_config_word(0, dfn, PCI_CLASS_DEVICE, &class) && if ((!a->read_config_word(0, dfn, PCI_CLASS_DEVICE, &x) &&
class == PCI_CLASS_BRIDGE_HOST) x == PCI_CLASS_BRIDGE_HOST) ||
(!a->read_config_word(0, dfn, PCI_VENDOR_ID, &x) &&
x == PCI_VENDOR_ID_INTEL))
return 1; return 1;
DBG("PCI: Sanity check failed\n"); DBG("PCI: Sanity check failed\n");
return 0; return 0;
...@@ -945,7 +953,7 @@ __initfunc(void pcibios_fixup_ghosts(struct pci_bus *b)) ...@@ -945,7 +953,7 @@ __initfunc(void pcibios_fixup_ghosts(struct pci_bus *b))
__initfunc(void pcibios_fixup_peer_bridges(void)) __initfunc(void pcibios_fixup_peer_bridges(void))
{ {
struct pci_bus *b = &pci_root; struct pci_bus *b = &pci_root;
int i, cnt=-1; int i, n, cnt=-1;
struct pci_dev *d; struct pci_dev *d;
#ifdef CONFIG_PCI_DIRECT #ifdef CONFIG_PCI_DIRECT
...@@ -960,8 +968,8 @@ __initfunc(void pcibios_fixup_peer_bridges(void)) ...@@ -960,8 +968,8 @@ __initfunc(void pcibios_fixup_peer_bridges(void))
for(d=b->devices; d; d=d->sibling) for(d=b->devices; d; d=d->sibling)
if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST) if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST)
cnt++; cnt++;
do { n = b->subordinate + 1;
int n = b->subordinate+1; while (n <= 0xff) {
int found = 0; int found = 0;
u16 l; u16 l;
for(i=0; i<256; i += 8) for(i=0; i<256; i += 8)
...@@ -973,8 +981,9 @@ __initfunc(void pcibios_fixup_peer_bridges(void)) ...@@ -973,8 +981,9 @@ __initfunc(void pcibios_fixup_peer_bridges(void))
l == PCI_CLASS_BRIDGE_HOST) l == PCI_CLASS_BRIDGE_HOST)
cnt++; cnt++;
} }
if (found && cnt > 0) { if (cnt-- <= 0)
cnt--; break;
if (found) {
printk("PCI: Discovered primary peer bus %02x\n", n); printk("PCI: Discovered primary peer bus %02x\n", n);
b = kmalloc(sizeof(*b), GFP_KERNEL); b = kmalloc(sizeof(*b), GFP_KERNEL);
memset(b, 0, sizeof(*b)); memset(b, 0, sizeof(*b));
...@@ -983,9 +992,10 @@ __initfunc(void pcibios_fixup_peer_bridges(void)) ...@@ -983,9 +992,10 @@ __initfunc(void pcibios_fixup_peer_bridges(void))
b->number = b->secondary = n; b->number = b->secondary = n;
b->subordinate = 0xff; b->subordinate = 0xff;
b->subordinate = pci_scan_bus(b); b->subordinate = pci_scan_bus(b);
break; n = b->subordinate;
}
n++;
} }
} while (i < 256);
} }
/* /*
...@@ -1146,11 +1156,11 @@ __initfunc(char *pcibios_setup(char *str)) ...@@ -1146,11 +1156,11 @@ __initfunc(char *pcibios_setup(char *str))
#endif #endif
#ifdef CONFIG_PCI_DIRECT #ifdef CONFIG_PCI_DIRECT
else if (!strcmp(str, "conf1")) { else if (!strcmp(str, "conf1")) {
pci_probe = PCI_PROBE_CONF1; pci_probe = PCI_PROBE_CONF1 | PCI_NO_CHECKS;
return NULL; return NULL;
} }
else if (!strcmp(str, "conf2")) { else if (!strcmp(str, "conf2")) {
pci_probe = PCI_PROBE_CONF2; pci_probe = PCI_PROBE_CONF2 | PCI_NO_CHECKS;
return NULL; return NULL;
} }
#endif #endif
......
...@@ -371,9 +371,16 @@ static int __init MPBIOS_trigger(int idx) ...@@ -371,9 +371,16 @@ static int __init MPBIOS_trigger(int idx)
{ {
switch (mp_bus_id_to_type[bus]) switch (mp_bus_id_to_type[bus])
{ {
case MP_BUS_ISA: /* ISA pin, edge */ case MP_BUS_ISA: {
{ /* ISA pin, read the Edge/Level control register */
trigger = 0; 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; break;
} }
case MP_BUS_PCI: /* PCI pin, level */ case MP_BUS_PCI: /* PCI pin, level */
...@@ -1009,8 +1016,10 @@ static void do_edge_ioapic_IRQ(unsigned int irq, struct pt_regs * regs) ...@@ -1009,8 +1016,10 @@ static void do_edge_ioapic_IRQ(unsigned int irq, struct pt_regs * regs)
/* /*
* If there is no IRQ handler or it was disabled, exit early. * 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; return;
}
/* /*
* Edge triggered interrupts need to remember * Edge triggered interrupts need to remember
...@@ -1061,8 +1070,10 @@ static void do_level_ioapic_IRQ(unsigned int irq, struct pt_regs * regs) ...@@ -1061,8 +1070,10 @@ static void do_level_ioapic_IRQ(unsigned int irq, struct pt_regs * regs)
spin_unlock(&irq_controller_lock); spin_unlock(&irq_controller_lock);
/* Exit early if we had no action or it was disabled */ /* 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; return;
}
handle_IRQ_event(irq, regs, action); handle_IRQ_event(irq, regs, action);
......
...@@ -664,8 +664,10 @@ static void do_8259A_IRQ(unsigned int irq, struct pt_regs * regs) ...@@ -664,8 +664,10 @@ static void do_8259A_IRQ(unsigned int irq, struct pt_regs * regs)
spin_unlock(&irq_controller_lock); spin_unlock(&irq_controller_lock);
/* Exit early if we had no action or it was disabled */ /* 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; return;
}
handle_IRQ_event(irq, regs, action); handle_IRQ_event(irq, regs, action);
......
...@@ -426,8 +426,7 @@ static int msdos_partition(struct gendisk *hd, kdev_t dev, unsigned long first_s ...@@ -426,8 +426,7 @@ static int msdos_partition(struct gendisk *hd, kdev_t dev, unsigned long first_s
&& (q->sector & 63) == 1 && (q->sector & 63) == 1
&& (q->end_sector & 63) == 63) { && (q->end_sector & 63) == 63) {
unsigned int heads = q->end_head + 1; unsigned int heads = q->end_head + 1;
if (heads == 15 || heads == 16 || if (heads == 32 || heads == 64 ||
heads == 32 || heads == 64 ||
heads == 128 || heads == 240 || heads == 128 || heads == 240 ||
heads == 255) { heads == 255) {
(void) ide_xlate_1024(dev, heads, " [PTBL]"); (void) ide_xlate_1024(dev, heads, " [PTBL]");
......
...@@ -102,7 +102,7 @@ static struct esp_pio_buffer *free_pio_buf; ...@@ -102,7 +102,7 @@ static struct esp_pio_buffer *free_pio_buf;
#define WAKEUP_CHARS 1024 #define WAKEUP_CHARS 1024
static char *serial_name = "ESP serial driver"; 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); static DECLARE_TASK_QUEUE(tq_esp);
...@@ -2615,6 +2615,9 @@ __initfunc(int espserial_init(void)) ...@@ -2615,6 +2615,9 @@ __initfunc(int espserial_init(void))
} }
memset((void *)info, 0, sizeof(struct esp_struct)); 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; i = 0;
offset = 0; offset = 0;
...@@ -2644,8 +2647,6 @@ __initfunc(int espserial_init(void)) ...@@ -2644,8 +2647,6 @@ __initfunc(int espserial_init(void))
info->callout_termios = esp_callout_driver.init_termios; info->callout_termios = esp_callout_driver.init_termios;
info->normal_termios = esp_driver.init_termios; info->normal_termios = esp_driver.init_termios;
info->config.rx_timeout = rx_timeout; 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_on = flow_on;
info->config.flow_off = flow_off; info->config.flow_off = flow_off;
info->config.pio_threshold = pio_threshold; info->config.pio_threshold = pio_threshold;
...@@ -2681,6 +2682,9 @@ __initfunc(int espserial_init(void)) ...@@ -2681,6 +2682,9 @@ __initfunc(int espserial_init(void))
} }
memset((void *)info, 0, sizeof(struct esp_struct)); 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) { if (offset == 56) {
i++; i++;
......
...@@ -611,13 +611,18 @@ static char * __init initialize_kbd(void) ...@@ -611,13 +611,18 @@ static char * __init initialize_kbd(void)
void __init pckbd_init_hw(void) void __init pckbd_init_hw(void)
{ {
disable_irq(KEYBOARD_IRQ);
/* Flush any pending input. */ /* Flush any pending input. */
kbd_clear_input(); kbd_clear_input();
if (kbd_startup_reset) { if (kbd_startup_reset) {
char *msg = initialize_kbd(); char *msg = initialize_kbd();
if (msg) if (msg) {
printk(KERN_WARNING "initialize_kbd: %s\n", msg); printk(KERN_WARNING "initialize_kbd: %s\n", msg);
aux_device_present = 0;
return;
}
} }
request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL); request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL);
......
...@@ -1386,6 +1386,7 @@ ppp_ioctl(struct ppp *ppp, unsigned int param2, unsigned long param3) ...@@ -1386,6 +1386,7 @@ ppp_ioctl(struct ppp *ppp, unsigned int param2, unsigned long param3)
break; break;
if (temp_i < PPP_MRU) if (temp_i < PPP_MRU)
temp_i = PPP_MRU; temp_i = PPP_MRU;
ppp->mru = temp_i;
if (ppp->flags & SC_DEBUG) if (ppp->flags & SC_DEBUG)
printk(KERN_INFO printk(KERN_INFO
"ppp_ioctl: set mru to %x\n", temp_i); "ppp_ioctl: set mru to %x\n", temp_i);
......
...@@ -65,8 +65,7 @@ static imm_struct imm_hosts[NO_HOSTS] = ...@@ -65,8 +65,7 @@ static imm_struct imm_hosts[NO_HOSTS] =
#define IMM_BASE(x) imm_hosts[(x)].base #define IMM_BASE(x) imm_hosts[(x)].base
int base[NO_HOSTS] = int parbus_base[NO_HOSTS] = {0x03bc, 0x0378, 0x0278, 0x0000};
{0x03bc, 0x0378, 0x0278, 0x0000};
void imm_wakeup(void *ref) void imm_wakeup(void *ref)
{ {
......
...@@ -18,6 +18,9 @@ ...@@ -18,6 +18,9 @@
* *
* Fixes: Dmitry Gorodchanin <pgmdsg@ibi.com>, 11 Feb 96 * Fixes: Dmitry Gorodchanin <pgmdsg@ibi.com>, 11 Feb 96
* *
* Revised list management to avoid races
* -- Bill Hawes, <whawes@star.net>, 9/98
*
* (C) Copyright 1994 - 1997 Marco van Wieringen * (C) Copyright 1994 - 1997 Marco van Wieringen
*/ */
...@@ -50,12 +53,29 @@ static char *quotatypes[] = INITQFNAMES; ...@@ -50,12 +53,29 @@ static char *quotatypes[] = INITQFNAMES;
static kmem_cache_t *dquot_cachep; static kmem_cache_t *dquot_cachep;
static struct dquot *dquot_hash[NR_DQHASH]; /*
static struct free_dquot_queue { * Dquot List Management:
struct dquot *head; * The quota code uses three lists for dquot management: the inuse_list,
struct dquot **last; * free_dquots, and dquot_hash[] array. A single dquot structure may be
} free_dquots = { NULL, &free_dquots.head }; * 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; static struct dquot *inuse_list = NULL;
LIST_HEAD(free_dquots);
static struct dquot *dquot_hash[NR_DQHASH];
static int dquot_updating[NR_DQHASH]; static int dquot_updating[NR_DQHASH];
static struct dqstats dqstats; static struct dqstats dqstats;
...@@ -128,37 +148,29 @@ static inline struct dquot *find_dquot(unsigned int hashent, kdev_t dev, unsigne ...@@ -128,37 +148,29 @@ static inline struct dquot *find_dquot(unsigned int hashent, kdev_t dev, unsigne
return dquot; return dquot;
} }
/* Add a dquot to the head of the free list */
static inline void put_dquot_head(struct dquot *dquot) static inline void put_dquot_head(struct dquot *dquot)
{ {
if ((dquot->dq_next = free_dquots.head) != NULL) list_add(&dquot->dq_free, &free_dquots);
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;
nr_free_dquots++; nr_free_dquots++;
} }
/* Add a dquot to the tail of the free list */
static inline void put_dquot_last(struct dquot *dquot) static inline void put_dquot_last(struct dquot *dquot)
{ {
dquot->dq_next = NULL; list_add(&dquot->dq_free, free_dquots.prev);
dquot->dq_pprev = free_dquots.last;
*free_dquots.last = dquot;
free_dquots.last = &dquot->dq_next;
nr_free_dquots++; nr_free_dquots++;
} }
static inline void remove_free_dquot(struct dquot *dquot) static inline void remove_free_dquot(struct dquot *dquot)
{ {
if (dquot->dq_pprev) { /* sanity check */
if (dquot->dq_next) if (list_empty(&dquot->dq_free)) {
dquot->dq_next->dq_pprev = dquot->dq_pprev; printk("remove_free_dquot: dquot not on free list??\n");
else
free_dquots.last = dquot->dq_pprev;
*dquot->dq_pprev = dquot->dq_next;
dquot->dq_pprev = NULL;
nr_free_dquots--;
} }
list_del(&dquot->dq_free);
INIT_LIST_HEAD(&dquot->dq_free);
nr_free_dquots--;
} }
static inline void put_inuse(struct dquot *dquot) static inline void put_inuse(struct dquot *dquot)
...@@ -169,6 +181,7 @@ static inline void put_inuse(struct dquot *dquot) ...@@ -169,6 +181,7 @@ static inline void put_inuse(struct dquot *dquot)
dquot->dq_pprev = &inuse_list; dquot->dq_pprev = &inuse_list;
} }
#if 0 /* currently not needed */
static inline void remove_inuse(struct dquot *dquot) static inline void remove_inuse(struct dquot *dquot)
{ {
if (dquot->dq_pprev) { if (dquot->dq_pprev) {
...@@ -178,6 +191,7 @@ static inline void remove_inuse(struct dquot *dquot) ...@@ -178,6 +191,7 @@ static inline void remove_inuse(struct dquot *dquot)
dquot->dq_pprev = NULL; dquot->dq_pprev = NULL;
} }
} }
#endif
static void __wait_on_dquot(struct dquot *dquot) static void __wait_on_dquot(struct dquot *dquot)
{ {
...@@ -187,7 +201,6 @@ static void __wait_on_dquot(struct dquot *dquot) ...@@ -187,7 +201,6 @@ static void __wait_on_dquot(struct dquot *dquot)
repeat: repeat:
current->state = TASK_UNINTERRUPTIBLE; current->state = TASK_UNINTERRUPTIBLE;
if (dquot->dq_flags & DQ_LOCKED) { if (dquot->dq_flags & DQ_LOCKED) {
dquot->dq_flags |= DQ_WANT;
schedule(); schedule();
goto repeat; goto repeat;
} }
...@@ -210,24 +223,16 @@ static inline void lock_dquot(struct dquot *dquot) ...@@ -210,24 +223,16 @@ static inline void lock_dquot(struct dquot *dquot)
static inline void unlock_dquot(struct dquot *dquot) static inline void unlock_dquot(struct dquot *dquot)
{ {
dquot->dq_flags &= ~DQ_LOCKED; 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) static void write_dquot(struct dquot *dquot)
{ {
short type; short type = dquot->dq_type;
struct file *filp; struct file *filp = dquot->dq_mnt->mnt_dquot.files[type];
mm_segment_t fs; mm_segment_t fs;
loff_t offset; loff_t offset;
ssize_t ret;
type = dquot->dq_type;
filp = dquot->dq_mnt->mnt_dquot.files[type];
if (!(dquot->dq_flags & DQ_MOD) || (filp == (struct file *)NULL))
return;
lock_dquot(dquot); lock_dquot(dquot);
down(&dquot->dq_mnt->mnt_dquot.semaphore); down(&dquot->dq_mnt->mnt_dquot.semaphore);
...@@ -235,8 +240,18 @@ static void write_dquot(struct dquot *dquot) ...@@ -235,8 +240,18 @@ static void write_dquot(struct dquot *dquot)
fs = get_fs(); fs = get_fs();
set_fs(KERNEL_DS); set_fs(KERNEL_DS);
if (filp->f_op->write(filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk), &offset) == sizeof(struct dqblk)) /*
* Note: clear the DQ_MOD flag unconditionally,
* so we don't loop forever on failure.
*/
dquot->dq_flags &= ~DQ_MOD; 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); up(&dquot->dq_mnt->mnt_dquot.semaphore);
set_fs(fs); set_fs(fs);
...@@ -274,73 +289,86 @@ static void read_dquot(struct dquot *dquot) ...@@ -274,73 +289,86 @@ static void read_dquot(struct dquot *dquot)
dqstats.reads++; 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) void clear_dquot(struct dquot *dquot)
{ {
struct wait_queue *wait; /* unhash it first */
/* 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_dquot(dquot); unhash_dquot(dquot);
wait = dquot->dq_wait; dquot->dq_mnt = NULL;
memset(dquot, 0, sizeof(*dquot)); barrier(); dquot->dq_flags = 0;
dquot->dq_wait = wait; dquot->dq_referenced = 0;
put_dquot_head(dquot); memset(&dquot->dq_dqb, 0, sizeof(struct dqblk));
} }
void invalidate_dquots(kdev_t dev, short type) void invalidate_dquots(kdev_t dev, short type)
{ {
struct dquot *dquot, *next = NULL; struct dquot *dquot, *next = inuse_list;
int pass = 0; int need_restart;
dquot = free_dquots.head; restart:
repeat: need_restart = 0;
while (dquot) { while ((dquot = next) != NULL) {
next = dquot->dq_next; next = dquot->dq_next;
if (dquot->dq_dev != dev || dquot->dq_type != type) if (dquot->dq_dev != dev)
goto next; continue;
clear_dquot(dquot); if (dquot->dq_type != type)
next: continue;
dquot = next; if (dquot->dq_flags & DQ_LOCKED) {
} __wait_on_dquot(dquot);
if (pass == 0) { /* Set the flag for another pass. */
dquot = inuse_list; need_restart = 1;
pass = 1; /*
goto repeat; * 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) int sync_dquots(kdev_t dev, short type)
{ {
struct dquot *dquot, *next; struct dquot *dquot, *next = inuse_list;
int pass = 0; int need_restart;
dquot = free_dquots.head; restart:
repeat: need_restart = 0;
while (dquot) { while ((dquot = next) != NULL) {
next = dquot->dq_next; next = dquot->dq_next;
if ((dev && dquot->dq_dev != dev) || if (dev && dquot->dq_dev != dev)
(type != -1 && dquot->dq_type != type)) continue;
goto next; if (type != -1 && dquot->dq_type != type)
continue;
if (!(dquot->dq_flags & (DQ_LOCKED | DQ_MOD)))
continue;
wait_on_dquot(dquot); wait_on_dquot(dquot);
if (dquot->dq_flags & DQ_MOD) if (dquot->dq_flags & DQ_MOD)
write_dquot(dquot); write_dquot(dquot);
next: /* Set the flag for another pass. */
dquot = next; 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++; dqstats.syncs++;
return(0); return(0);
} }
...@@ -349,40 +377,41 @@ void dqput(struct dquot *dquot) ...@@ -349,40 +377,41 @@ void dqput(struct dquot *dquot)
{ {
if (!dquot) if (!dquot)
return; 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 * 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. * dquot that is put back on to the freelist.
*/ */
if (dquot->dq_mnt != (struct vfsmount *)NULL) { if (dquot->dq_mnt != (struct vfsmount *)NULL) {
dqstats.drops++; 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: we_slept:
wait_on_dquot(dquot);
if (dquot->dq_count > 1) { if (dquot->dq_count > 1) {
dquot->dq_count--; dquot->dq_count--;
return; return;
} else { }
wake_up(&dquot_wait);
if (dquot->dq_flags & DQ_MOD) { if (dquot->dq_flags & DQ_MOD) {
write_dquot(dquot); write_dquot(dquot);
wait_on_dquot(dquot);
goto we_slept; goto we_slept;
} }
} }
}
/* sanity check */
if (!list_empty(&dquot->dq_free)) {
printk("dqput: dquot already on free list??\n");
}
if (--dquot->dq_count == 0) { if (--dquot->dq_count == 0) {
remove_inuse(dquot); /* Place at end of LRU free queue */
put_dquot_last(dquot); /* Place at end of LRU free queue */ put_dquot_last(dquot);
wake_up(&dquot_wait);
} }
return; return;
...@@ -400,45 +429,43 @@ static void grow_dquots(void) ...@@ -400,45 +429,43 @@ static void grow_dquots(void)
nr_dquots++; nr_dquots++;
memset((caddr_t)dquot, 0, sizeof(struct dquot)); memset((caddr_t)dquot, 0, sizeof(struct dquot));
/* all dquots go on the inuse_list */
put_inuse(dquot);
put_dquot_head(dquot); put_dquot_head(dquot);
cnt--; cnt--;
} }
} }
static struct dquot *find_best_candidate_weighted(struct dquot *dquot) static struct dquot *find_best_candidate_weighted(void)
{ {
int limit, myscore; struct list_head *tmp = &free_dquots;
unsigned long bestscore; struct dquot *dquot, *best = NULL;
struct dquot *best = NULL; unsigned long myscore, bestscore = ~0U;
int limit = (nr_free_dquots > 128) ? nr_free_dquots >> 2 : 32;
if (dquot) {
bestscore = 2147483647; while ((tmp = tmp->next) != &free_dquots && --limit) {
limit = nr_free_dquots >> 2; dquot = list_entry(tmp, struct dquot, dq_free);
do { if (dquot->dq_flags & (DQ_LOCKED | DQ_MOD))
if (!((dquot->dq_flags & DQ_LOCKED) || (dquot->dq_flags & DQ_MOD))) { continue;
myscore = dquot->dq_referenced; myscore = dquot->dq_referenced;
if (myscore < bestscore) { if (myscore < bestscore) {
bestscore = myscore; bestscore = myscore;
best = dquot; best = dquot;
} }
} }
dquot = dquot->dq_next;
} while (dquot && --limit);
}
return best; 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) { while ((tmp = tmp->next) != &free_dquots && --limit) {
limit = nr_free_dquots >> 5; dquot = list_entry(tmp, struct dquot, dq_free);
do {
if (dquot->dq_referenced == 0) if (dquot->dq_referenced == 0)
return dquot; return dquot;
dquot = dquot->dq_next;
} while (dquot && --limit);
} }
return NULL; return NULL;
} }
...@@ -446,42 +473,56 @@ static inline struct dquot *find_best_free(struct dquot *dquot) ...@@ -446,42 +473,56 @@ static inline struct dquot *find_best_free(struct dquot *dquot)
struct dquot *get_empty_dquot(void) struct dquot *get_empty_dquot(void)
{ {
struct dquot *dquot; struct dquot *dquot;
int count;
repeat: repeat:
dquot = find_best_free(free_dquots.head); dquot = find_best_free();
if (!dquot) if (!dquot)
goto pressure; goto pressure;
got_it: got_it:
dquot->dq_count++; if (dquot->dq_flags & (DQ_LOCKED | DQ_MOD)) {
wait_on_dquot(dquot); wait_on_dquot(dquot);
unhash_dquot(dquot); if (dquot->dq_flags & DQ_MOD)
remove_free_dquot(dquot); 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; dquot->dq_count = 1;
/* unhash and selectively clear the structure */
put_inuse(dquot); clear_dquot(dquot);
return dquot; return dquot;
pressure: pressure:
if (nr_dquots < max_dquots) { if (nr_dquots < max_dquots) {
grow_dquots(); grow_dquots();
goto repeat; goto repeat;
} }
dquot = find_best_candidate_weighted(free_dquots.head); dquot = find_best_candidate_weighted();
if (!dquot) { if (dquot)
printk("VFS: No free dquots, contact mvw@planets.elm.net\n"); goto got_it;
sleep_on(&dquot_wait); /*
* 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 repeat;
} }
if (dquot->dq_flags & DQ_LOCKED) {
wait_on_dquot(dquot); printk("VFS: No free dquots, contact mvw@planets.elm.net\n");
goto repeat; sleep_on(&dquot_wait);
} else if (dquot->dq_flags & DQ_MOD) {
write_dquot(dquot);
goto repeat; goto repeat;
}
goto got_it;
} }
struct dquot *dqget(kdev_t dev, unsigned int id, short type) struct dquot *dqget(kdev_t dev, unsigned int id, short type)
...@@ -507,12 +548,12 @@ struct dquot *dqget(kdev_t dev, unsigned int id, short type) ...@@ -507,12 +548,12 @@ struct dquot *dqget(kdev_t dev, unsigned int id, short type)
dquot->dq_type = type; dquot->dq_type = type;
dquot->dq_dev = dev; dquot->dq_dev = dev;
dquot->dq_mnt = vfsmnt; dquot->dq_mnt = vfsmnt;
read_dquot(dquot); /* hash it first so it can be found */
hash_dquot(dquot); hash_dquot(dquot);
read_dquot(dquot);
} else { } else {
if (!dquot->dq_count++) { if (!dquot->dq_count++) {
remove_free_dquot(dquot); remove_free_dquot(dquot);
put_inuse(dquot);
} else } else
dqstats.cache_hits++; dqstats.cache_hits++;
wait_on_dquot(dquot); wait_on_dquot(dquot);
...@@ -546,6 +587,7 @@ static void add_dquot_ref(kdev_t dev, short type) ...@@ -546,6 +587,7 @@ static void add_dquot_ref(kdev_t dev, short type)
inode = filp->f_dentry->d_inode; inode = filp->f_dentry->d_inode;
if (!inode) if (!inode)
continue; continue;
/* N.B. race problem -- filp could become unused */
if (filp->f_mode & FMODE_WRITE) { if (filp->f_mode & FMODE_WRITE) {
sb->dq_op->initialize(inode, type); sb->dq_op->initialize(inode, type);
inode->i_flags |= S_QUOTA; inode->i_flags |= S_QUOTA;
...@@ -558,10 +600,16 @@ static void reset_dquot_ptrs(kdev_t dev, short type) ...@@ -558,10 +600,16 @@ static void reset_dquot_ptrs(kdev_t dev, short type)
struct super_block *sb = get_super(dev); struct super_block *sb = get_super(dev);
struct file *filp; struct file *filp;
struct inode *inode; struct inode *inode;
struct dquot *dquot;
int cnt;
if (!sb || !sb->dq_op) if (!sb || !sb->dq_op)
return; /* nothing to do */ return; /* nothing to do */
restart:
/* free any quota for unused dentries */
shrink_dcache_sb(sb);
for (filp = inuse_filps; filp; filp = filp->f_next) { for (filp = inuse_filps; filp; filp = filp->f_next) {
if (!filp->f_dentry) if (!filp->f_dentry)
continue; continue;
...@@ -570,10 +618,25 @@ static void reset_dquot_ptrs(kdev_t dev, short type) ...@@ -570,10 +618,25 @@ static void reset_dquot_ptrs(kdev_t dev, short type)
inode = filp->f_dentry->d_inode; inode = filp->f_dentry->d_inode;
if (!inode) if (!inode)
continue; continue;
/*
* Note: we restart after each blocking operation,
* as the inuse_filps list may have changed.
*/
if (IS_QUOTAINIT(inode)) { if (IS_QUOTAINIT(inode)) {
sb->dq_op->drop(inode); dquot = inode->i_dquot[type];
inode->i_dquot[type] = NODQUOT; 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; inode->i_flags &= ~S_QUOTA;
put_it:
if (dquot != NODQUOT) {
dqput(dquot);
/* we may have blocked ... */
goto restart;
}
} }
} }
} }
...@@ -638,7 +701,8 @@ static inline char ignore_hardlimit(struct dquot *dquot, uid_t initiator) ...@@ -638,7 +701,8 @@ static inline char ignore_hardlimit(struct dquot *dquot, uid_t initiator)
return(initiator == 0 && dquot->dq_mnt->mnt_dquot.rsquash[dquot->dq_type] == 0); 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) if (inodes <= 0 || dquot->dq_flags & DQ_FAKE)
return(QUOTA_OK); return(QUOTA_OK);
...@@ -682,7 +746,8 @@ static int check_idq(struct dquot *dquot, short type, u_long short inodes, uid_t ...@@ -682,7 +746,8 @@ static int check_idq(struct dquot *dquot, short type, u_long short inodes, uid_t
return(QUOTA_OK); 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) if (blocks <= 0 || dquot->dq_flags & DQ_FAKE)
return(QUOTA_OK); return(QUOTA_OK);
...@@ -732,15 +797,15 @@ static int check_bdq(struct dquot *dquot, short type, u_long blocks, uid_t initi ...@@ -732,15 +797,15 @@ static int check_bdq(struct dquot *dquot, short type, u_long blocks, uid_t initi
*/ */
static int set_dqblk(kdev_t dev, int id, short type, int flags, struct dqblk *dqblk) static int set_dqblk(kdev_t dev, int id, short type, int flags, struct dqblk *dqblk)
{ {
int error;
struct dquot *dquot; struct dquot *dquot;
int error = -EFAULT;
struct dqblk dq_dqblk; struct dqblk dq_dqblk;
if (dqblk == (struct dqblk *)NULL) if (dqblk == (struct dqblk *)NULL)
return(-EFAULT); return error;
if (flags & QUOTA_SYSCALL) { 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); return(error);
} else } else
memcpy((caddr_t)&dq_dqblk, (caddr_t)dqblk, sizeof(struct dqblk)); memcpy((caddr_t)&dq_dqblk, (caddr_t)dqblk, sizeof(struct dqblk));
...@@ -793,26 +858,35 @@ static int set_dqblk(kdev_t dev, int id, short type, int flags, struct dqblk *dq ...@@ -793,26 +858,35 @@ static int set_dqblk(kdev_t dev, int id, short type, int flags, struct dqblk *dq
static int get_quota(kdev_t dev, int id, short type, struct dqblk *dqblk) static int get_quota(kdev_t dev, int id, short type, struct dqblk *dqblk)
{ {
struct dquot *dquot; struct dquot *dquot;
int error; int error = -ESRCH;
if (dev_has_quota_enabled(dev, type)) { if (!dev_has_quota_enabled(dev, type))
if (dqblk == (struct dqblk *)NULL) goto out;
return(-EFAULT); dquot = dqget(dev, id, type);
if (dquot == NODQUOT)
goto out;
if ((dquot = dqget(dev, id, type)) != NODQUOT) { error = -EFAULT;
error = copy_to_user((caddr_t)dqblk, (caddr_t)&dquot->dq_dqb, sizeof(struct dqblk)); if (dqblk && !copy_to_user(dqblk, &dquot->dq_dqb, sizeof(struct dqblk)))
error = 0;
dqput(dquot); dqput(dquot);
return(error); out:
} return error;
}
return(-ESRCH);
} }
static int get_stats(caddr_t addr) static int get_stats(caddr_t addr)
{ {
int error = -EFAULT;
struct dqstats stats;
dqstats.allocated_dquots = nr_dquots; dqstats.allocated_dquots = nr_dquots;
dqstats.free_dquots = nr_free_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) static int quota_root_squash(kdev_t dev, short type, int *addr)
...@@ -823,11 +897,12 @@ static int quota_root_squash(kdev_t dev, short type, int *addr) ...@@ -823,11 +897,12 @@ static int quota_root_squash(kdev_t dev, short type, int *addr)
if ((vfsmnt = lookup_vfsmnt(dev)) == (struct vfsmount *)NULL) if ((vfsmnt = lookup_vfsmnt(dev)) == (struct vfsmount *)NULL)
return(-ENODEV); return(-ENODEV);
if ((error = copy_from_user((caddr_t)&new_value, (caddr_t)addr, sizeof(int))) != 0) error = -EFAULT;
return(error); if (!copy_from_user(&new_value, addr, sizeof(int))) {
vfsmnt->mnt_dquot.rsquash[type] = new_value; vfsmnt->mnt_dquot.rsquash[type] = new_value;
return(0); error = 0;
}
return error;
} }
/* /*
...@@ -856,6 +931,8 @@ static u_long isize_to_blocks(size_t isize, size_t blksize) ...@@ -856,6 +931,8 @@ static u_long isize_to_blocks(size_t isize, size_t blksize)
/* /*
* Externally referenced functions through dquot_operations in inode. * Externally referenced functions through dquot_operations in inode.
*
* Note: this is a blocking operation.
*/ */
void dquot_initialize(struct inode *inode, short type) void dquot_initialize(struct inode *inode, short type)
{ {
...@@ -894,6 +971,11 @@ void dquot_initialize(struct inode *inode, short type) ...@@ -894,6 +971,11 @@ void dquot_initialize(struct inode *inode, short type)
} }
} }
/*
* Release all quota for the specified inode.
*
* Note: this is a blocking operation.
*/
void dquot_drop(struct inode *inode) void dquot_drop(struct inode *inode)
{ {
struct dquot *dquot; struct dquot *dquot;
...@@ -909,7 +991,11 @@ void dquot_drop(struct inode *inode) ...@@ -909,7 +991,11 @@ void dquot_drop(struct inode *inode)
} }
} }
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; unsigned short cnt;
struct tty_struct *tty = current->tty; struct tty_struct *tty = current->tty;
...@@ -930,6 +1016,9 @@ int dquot_alloc_block(const struct inode *inode, unsigned long number, uid_t ini ...@@ -930,6 +1016,9 @@ int dquot_alloc_block(const struct inode *inode, unsigned long number, uid_t ini
return(QUOTA_OK); return(QUOTA_OK);
} }
/*
* Note: this is a blocking operation.
*/
int dquot_alloc_inode(const struct inode *inode, unsigned long number, uid_t initiator) int dquot_alloc_inode(const struct inode *inode, unsigned long number, uid_t initiator)
{ {
unsigned short cnt; unsigned short cnt;
...@@ -951,6 +1040,9 @@ int dquot_alloc_inode(const struct inode *inode, unsigned long number, uid_t ini ...@@ -951,6 +1040,9 @@ int dquot_alloc_inode(const struct inode *inode, unsigned long number, uid_t ini
return(QUOTA_OK); return(QUOTA_OK);
} }
/*
* Note: this is a blocking operation.
*/
void dquot_free_block(const struct inode *inode, unsigned long number) void dquot_free_block(const struct inode *inode, unsigned long number)
{ {
unsigned short cnt; unsigned short cnt;
...@@ -962,6 +1054,9 @@ void dquot_free_block(const struct inode *inode, unsigned long number) ...@@ -962,6 +1054,9 @@ void dquot_free_block(const struct inode *inode, unsigned long number)
} }
} }
/*
* Note: this is a blocking operation.
*/
void dquot_free_inode(const struct inode *inode, unsigned long number) void dquot_free_inode(const struct inode *inode, unsigned long number)
{ {
unsigned short cnt; unsigned short cnt;
...@@ -975,6 +1070,8 @@ void dquot_free_inode(const struct inode *inode, unsigned long number) ...@@ -975,6 +1070,8 @@ void dquot_free_inode(const struct inode *inode, unsigned long number)
/* /*
* Transfer the number of inode and blocks from one diskquota to an other. * 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) int dquot_transfer(struct inode *inode, struct iattr *iattr, char direction, uid_t initiator)
{ {
...@@ -1029,8 +1126,8 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr, char direction, uid ...@@ -1029,8 +1126,8 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr, char direction, uid
} }
/* /*
* Finally perform the needed transfer from transfer_from to transfer_to. * Finally perform the needed transfer from transfer_from to transfer_to,
* And release any pointer to dquots not needed anymore. * and release any pointers to dquots not needed anymore.
*/ */
for (cnt = 0; cnt < MAXQUOTAS; cnt++) { for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
/* /*
...@@ -1050,9 +1147,10 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr, char direction, uid ...@@ -1050,9 +1147,10 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr, char direction, uid
} }
if (inode->i_dquot[cnt] != NODQUOT) { if (inode->i_dquot[cnt] != NODQUOT) {
dqput(transfer_from[cnt]); struct dquot *temp = inode->i_dquot[cnt];
dqput(inode->i_dquot[cnt]);
inode->i_dquot[cnt] = transfer_to[cnt]; inode->i_dquot[cnt] = transfer_to[cnt];
dqput(temp);
dqput(transfer_from[cnt]);
} else { } else {
dqput(transfer_from[cnt]); dqput(transfer_from[cnt]);
dqput(transfer_to[cnt]); dqput(transfer_to[cnt]);
...@@ -1082,8 +1180,8 @@ void __init dquot_init_hash(void) ...@@ -1082,8 +1180,8 @@ void __init dquot_init_hash(void)
* Definitions of diskquota operations. * Definitions of diskquota operations.
*/ */
struct dquot_operations dquot_operations = { struct dquot_operations dquot_operations = {
dquot_initialize, dquot_initialize, /* mandatory */
dquot_drop, dquot_drop, /* mandatory */
dquot_alloc_block, dquot_alloc_block,
dquot_alloc_inode, dquot_alloc_inode,
dquot_free_block, dquot_free_block,
...@@ -1121,30 +1219,47 @@ static inline void reset_enable_flags(struct vfsmount *vfsmnt, short type) ...@@ -1121,30 +1219,47 @@ static inline void reset_enable_flags(struct vfsmount *vfsmnt, short type)
int quota_off(kdev_t dev, short type) int quota_off(kdev_t dev, short type)
{ {
struct vfsmount *vfsmnt; struct vfsmount *vfsmnt;
struct file *filp;
short cnt; short cnt;
for (cnt = 0; cnt < MAXQUOTAS; cnt++) { for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
if (type != -1 && cnt != type) if (type != -1 && cnt != type)
continue; continue;
if ((vfsmnt = lookup_vfsmnt(dev)) == (struct vfsmount *)NULL || vfsmnt = lookup_vfsmnt(dev);
is_enabled(vfsmnt, cnt) == 0 || if (!vfsmnt)
vfsmnt->mnt_sb == (struct super_block *)NULL) goto out;
if (!vfsmnt->mnt_sb)
goto out;
if (!is_enabled(vfsmnt, cnt))
continue; 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); reset_dquot_ptrs(dev, cnt);
invalidate_dquots(dev, cnt); invalidate_dquots(dev, cnt);
fput(vfsmnt->mnt_dquot.files[cnt]); filp = vfsmnt->mnt_dquot.files[cnt];
reset_enable_flags(vfsmnt, cnt);
vfsmnt->mnt_dquot.files[cnt] = (struct file *)NULL; vfsmnt->mnt_dquot.files[cnt] = (struct file *)NULL;
vfsmnt->mnt_dquot.inode_expire[cnt] = 0; vfsmnt->mnt_dquot.inode_expire[cnt] = 0;
vfsmnt->mnt_dquot.block_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); return(0);
} }
...@@ -1316,10 +1431,9 @@ asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr) ...@@ -1316,10 +1431,9 @@ asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr)
flags |= QUOTA_SYSCALL; flags |= QUOTA_SYSCALL;
ret = -ESRCH;
if (dev_has_quota_enabled(dev, type)) if (dev_has_quota_enabled(dev, type))
ret = set_dqblk(dev, id, type, flags, (struct dqblk *) addr); ret = set_dqblk(dev, id, type, flags, (struct dqblk *) addr);
else
ret = -ESRCH;
out: out:
unlock_kernel(); unlock_kernel();
return ret; return ret;
......
...@@ -686,6 +686,12 @@ static int test_root(int a, int b) ...@@ -686,6 +686,12 @@ static int test_root(int a, int b)
} }
} }
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) void ext2_check_blocks_bitmap (struct super_block * sb)
{ {
struct buffer_head * bh; struct buffer_head * bh;
...@@ -716,7 +722,7 @@ void ext2_check_blocks_bitmap (struct super_block * sb) ...@@ -716,7 +722,7 @@ void ext2_check_blocks_bitmap (struct super_block * sb)
if (!(le32_to_cpu(sb->u.ext2_sb.s_feature_ro_compat) & if (!(le32_to_cpu(sb->u.ext2_sb.s_feature_ro_compat) &
EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) || 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)) if (!ext2_test_bit (0, bh->b_data))
ext2_error (sb, "ext2_check_blocks_bitmap", ext2_error (sb, "ext2_check_blocks_bitmap",
"Superblock in group %d " "Superblock in group %d "
......
...@@ -764,8 +764,8 @@ void cleanup_module(void) ...@@ -764,8 +764,8 @@ void cleanup_module(void)
int ext2_statfs (struct super_block * sb, struct statfs * buf, int bufsiz) int ext2_statfs (struct super_block * sb, struct statfs * buf, int bufsiz)
{ {
unsigned long overhead; unsigned long overhead;
unsigned long overhead_per_group;
struct statfs tmp; struct statfs tmp;
int ngroups, i;
if (test_opt (sb, MINIX_DF)) if (test_opt (sb, MINIX_DF))
overhead = 0; overhead = 0;
...@@ -773,13 +773,35 @@ int ext2_statfs (struct super_block * sb, struct statfs * buf, int bufsiz) ...@@ -773,13 +773,35 @@ int ext2_statfs (struct super_block * sb, struct statfs * buf, int bufsiz)
/* /*
* Compute the overhead (FS structures) * Compute the overhead (FS structures)
*/ */
overhead_per_group = 1 /* super block */ +
sb->u.ext2_sb.s_db_per_group /* descriptors */ + /*
1 /* block bitmap */ + * All of the blocks before first_data_block are
1 /* inode bitmap */ + * overhead
sb->u.ext2_sb.s_itb_per_group /* inode table */; */
overhead = le32_to_cpu(sb->u.ext2_sb.s_es->s_first_data_block) + overhead = le32_to_cpu(sb->u.ext2_sb.s_es->s_first_data_block);
sb->u.ext2_sb.s_groups_count * overhead_per_group;
/*
* 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; tmp.f_type = EXT2_SUPER_MAGIC;
......
...@@ -445,25 +445,31 @@ static unsigned int isofs_get_last_session(kdev_t dev) ...@@ -445,25 +445,31 @@ static unsigned int isofs_get_last_session(kdev_t dev)
return vol_desc_start; 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, struct super_block *isofs_read_super(struct super_block *s, void *data,
int silent) int silent)
{ {
struct buffer_head * bh = NULL, *pri_bh = NULL;
unsigned int blocksize;
unsigned int blocksize_bits;
kdev_t dev = s->s_dev; kdev_t dev = s->s_dev;
struct buffer_head * bh = NULL, *pri_bh = NULL;
struct hs_primary_descriptor * h_pri = NULL; struct hs_primary_descriptor * h_pri = NULL;
struct iso_primary_descriptor * pri = NULL; struct iso_primary_descriptor * pri = NULL;
struct iso_supplementary_descriptor *sec = NULL; struct iso_supplementary_descriptor *sec = NULL;
struct iso_directory_record * rootp; struct iso_directory_record * rootp;
int joliet_level = 0;
int high_sierra; int high_sierra;
int iso_blknum, block; int iso_blknum, block;
int joliet_level = 0;
int orig_zonesize; int orig_zonesize;
int table;
unsigned int blocksize, blocksize_bits;
unsigned int vol_desc_start; unsigned int vol_desc_start;
unsigned long first_data_zone;
struct inode * inode; struct inode * inode;
struct iso9660_options opt; struct iso9660_options opt;
int table;
MOD_INC_USE_COUNT; MOD_INC_USE_COUNT;
/* lock before any blocking operations */ /* lock before any blocking operations */
...@@ -592,7 +598,6 @@ struct super_block *isofs_read_super(struct super_block *s, void *data, ...@@ -592,7 +598,6 @@ struct super_block *isofs_read_super(struct super_block *s, void *data,
root_found: root_found:
brelse(pri_bh); brelse(pri_bh);
s->u.isofs_sb.s_joliet_level = joliet_level;
if (joliet_level && opt.rock == 'n') { if (joliet_level && opt.rock == 'n') {
/* This is the case of Joliet with the norock mount flag. /* This is the case of Joliet with the norock mount flag.
...@@ -623,10 +628,7 @@ struct super_block *isofs_read_super(struct super_block *s, void *data, ...@@ -623,10 +628,7 @@ struct super_block *isofs_read_super(struct super_block *s, void *data,
s->u.isofs_sb.s_ninodes = 0; /* No way to figure this out easily */ 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; orig_zonesize = s -> u.isofs_sb.s_log_zone_size;
/* /*
* If the zone size is smaller than the hardware sector size, * If the zone size is smaller than the hardware sector size,
* this is a fatal error. This would occur if the disc drive * this is a fatal error. This would occur if the disc drive
...@@ -637,6 +639,7 @@ struct super_block *isofs_read_super(struct super_block *s, void *data, ...@@ -637,6 +639,7 @@ struct super_block *isofs_read_super(struct super_block *s, void *data,
if(blocksize != 0 && orig_zonesize < blocksize) if(blocksize != 0 && orig_zonesize < blocksize)
goto out_bad_size; goto out_bad_size;
/* RDE: convert log zone size to bit shift */
switch (s -> u.isofs_sb.s_log_zone_size) switch (s -> u.isofs_sb.s_log_zone_size)
{ case 512: s -> u.isofs_sb.s_log_zone_size = 9; break; { case 512: s -> u.isofs_sb.s_log_zone_size = 9; break;
case 1024: s -> u.isofs_sb.s_log_zone_size = 10; break; case 1024: s -> u.isofs_sb.s_log_zone_size = 10; break;
...@@ -657,20 +660,44 @@ struct super_block *isofs_read_super(struct super_block *s, void *data, ...@@ -657,20 +660,44 @@ struct super_block *isofs_read_super(struct super_block *s, void *data,
/* RDE: data zone now byte offset! */ /* RDE: data zone now byte offset! */
s->u.isofs_sb.s_firstdatazone = ((isonum_733 (rootp->extent) + first_data_zone = ((isonum_733 (rootp->extent) +
isonum_711 (rootp->ext_attr_length)) isonum_711 (rootp->ext_attr_length))
<< s -> u.isofs_sb.s_log_zone_size); << s -> u.isofs_sb.s_log_zone_size);
s->u.isofs_sb.s_firstdatazone = first_data_zone;
#ifndef BEQUIET #ifndef BEQUIET
printk(KERN_DEBUG "Max size:%ld Log zone size:%ld\n", printk(KERN_DEBUG "Max size:%ld Log zone size:%ld\n",
s->u.isofs_sb.s_max_size, s->u.isofs_sb.s_max_size,
1UL << s->u.isofs_sb.s_log_zone_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 >> s -> u.isofs_sb.s_log_zone_size,
s->u.isofs_sb.s_firstdatazone); s->u.isofs_sb.s_firstdatazone);
if(high_sierra) if(high_sierra)
printk(KERN_DEBUG "Disc in High Sierra format.\n"); printk(KERN_DEBUG "Disc in High Sierra format.\n");
#endif #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 * 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 * read primitives really get it wrong in a bad way if we don't
...@@ -688,22 +715,15 @@ struct super_block *isofs_read_super(struct super_block *s, void *data, ...@@ -688,22 +715,15 @@ struct super_block *isofs_read_super(struct super_block *s, void *data,
* entries. By forcing the blocksize in this way, we ensure * entries. By forcing the blocksize in this way, we ensure
* that we will never be required to do this. * that we will never be required to do this.
*/ */
if( orig_zonesize != opt.blocksize ) if ( orig_zonesize != opt.blocksize ) {
{ set_blocksize(dev, orig_zonesize);
opt.blocksize = orig_zonesize;
blocksize_bits = 0;
{
int i = opt.blocksize;
while (i != 1){
blocksize_bits++;
i >>=1;
}
}
set_blocksize(dev, opt.blocksize);
#ifndef BEQUIET #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 #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; s->u.isofs_sb.s_nls_iocharset = NULL;
...@@ -732,8 +752,12 @@ struct super_block *isofs_read_super(struct super_block *s, void *data, ...@@ -732,8 +752,12 @@ struct super_block *isofs_read_super(struct super_block *s, void *data,
* as suid, so we merely allow them to set the default permissions. * as suid, so we merely allow them to set the default permissions.
*/ */
s->u.isofs_sb.s_mode = opt.mode & 0777; 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); inode = iget(s, s->u.isofs_sb.s_firstdatazone);
/* /*
...@@ -744,21 +768,17 @@ struct super_block *isofs_read_super(struct super_block *s, void *data, ...@@ -744,21 +768,17 @@ struct super_block *isofs_read_super(struct super_block *s, void *data,
* CD with Unicode names. Until someone sees such a beast, it * CD with Unicode names. Until someone sees such a beast, it
* will not be supported. * 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; joliet_level = 0;
} } else if (joliet_level) {
if (joliet_level) { s->u.isofs_sb.s_rock = 0;
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); 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); inode = iget(s, s->u.isofs_sb.s_firstdatazone);
s->u.isofs_sb.s_rock = 0; }
opt.rock = 'n';
} }
if (opt.check == 'u') { if (opt.check == 'u') {
...@@ -766,32 +786,46 @@ struct super_block *isofs_read_super(struct super_block *s, void *data, ...@@ -766,32 +786,46 @@ struct super_block *isofs_read_super(struct super_block *s, void *data,
if (joliet_level) opt.check = 'r'; if (joliet_level) opt.check = 'r';
else opt.check = 's'; 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); s->s_root = d_alloc_root(inode, NULL);
if (!(s->s_root)) if (!(s->s_root))
goto out_no_root; goto out_no_root;
table = 0; table = 0;
if (joliet_level) table += 2; if (joliet_level) table += 2;
if (opt.check == 'r') table++; if (opt.check == 'r') table++;
s->s_root->d_op = &isofs_dentry_ops[table]; s->s_root->d_op = &isofs_dentry_ops[table];
if(!check_disk_change(dev)) {
brelse(bh);
unlock_super(s); unlock_super(s);
return s; return s;
}
/*
* Disk changed? Free the root dentry and clean up ...
*/
dput(s->s_root);
goto out_freechar;
/* /*
* Display error message * Display error messages and free resources.
*/ */
out_no_root: out_bad_root:
printk(KERN_ERR "isofs_read_super: get root inode failed\n"); printk(KERN_WARNING "isofs_read_super: root inode not initialized\n");
goto out_iput; 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: out_bad_zone_size:
printk(KERN_WARNING "Bad logical zone size %ld\n", printk(KERN_WARNING "Bad logical zone size %ld\n",
s->u.isofs_sb.s_log_zone_size); s->u.isofs_sb.s_log_zone_size);
...@@ -808,23 +842,7 @@ struct super_block *isofs_read_super(struct super_block *s, void *data, ...@@ -808,23 +842,7 @@ struct super_block *isofs_read_super(struct super_block *s, void *data,
out_unknown_format: out_unknown_format:
if (!silent) if (!silent)
printk(KERN_WARNING "Unable to identify CD-ROM format.\n"); 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: out_freebh:
brelse(bh); brelse(bh);
out_unlock: out_unlock:
...@@ -945,101 +963,113 @@ static void test_and_set_uid(uid_t *p, uid_t value) ...@@ -945,101 +963,113 @@ static void test_and_set_uid(uid_t *p, uid_t value)
static int isofs_read_level3_size(struct inode * inode) static int isofs_read_level3_size(struct inode * inode)
{ {
unsigned long ino = inode->i_ino;
unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); 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 buffer_head * bh = NULL;
struct iso_directory_record * raw_inode = NULL; /* quiet gcc */ int block = 0;
unsigned char *pnt = NULL; int i = 0;
void *cpnt = NULL; void *cpnt;
int block = 0; /* Quiet GCC */ struct iso_directory_record * raw_inode;
unsigned long ino;
int i;
inode->i_size = 0; inode->i_size = 0;
inode->u.isofs_i.i_next_section_ino = 0; inode->u.isofs_i.i_next_section_ino = 0;
ino = inode->i_ino;
i = 0;
do { do {
if(i > 100) { unsigned char *pnt;
printk("isofs_read_level3_size: More than 100 file sections ?!?, aborting...\n" unsigned int reclen;
"isofs_read_level3_size: inode=%lu ino=%lu\n", inode->i_ino, ino); int offset = (ino & (bufsize - 1));
return 0;
}
if(bh == NULL || block != ino >> ISOFS_BUFFER_BITS(inode)) { cpnt = NULL;
if(bh) brelse(bh); /* Check whether to update our buffer */
if (block != ino >> ISOFS_BUFFER_BITS(inode)) {
block = ino >> ISOFS_BUFFER_BITS(inode); block = ino >> ISOFS_BUFFER_BITS(inode);
if (!(bh=bread(inode->i_dev,block, bufsize))) { brelse(bh);
printk("unable to read i-node block"); bh = bread(inode->i_dev, block, bufsize);
return 1; 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;
/* 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){ /* Check whether the raw inode spans the buffer ... */
int frag1, offset; if (offset + reclen > bufsize){
int frag1 = bufsize - offset;
offset = (ino & (bufsize - 1)); cpnt = kmalloc(reclen, GFP_KERNEL);
frag1 = bufsize - offset; if (cpnt == NULL)
cpnt = kmalloc(*pnt,GFP_KERNEL); goto out_nomem;
if (cpnt == NULL) { memcpy(cpnt, pnt, frag1);
printk(KERN_INFO "NoMem ISO inode %lu\n",inode->i_ino);
brelse(bh);
return 1;
}
memcpy(cpnt, bh->b_data + offset, frag1);
brelse(bh); brelse(bh);
if (!(bh = bread(inode->i_dev,++block, bufsize))) { bh = bread(inode->i_dev, ++block, bufsize);
kfree(cpnt); if (!bh)
printk("unable to read i-node block"); goto out_noread;
return 1; offset += reclen - bufsize;
}
offset += *pnt - bufsize;
memcpy((char *)cpnt+frag1, bh->b_data, offset); 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); inode->i_size += isonum_733 (raw_inode->size);
if(i == 1) inode->u.isofs_i.i_next_section_ino = ino; if(i == 1) inode->u.isofs_i.i_next_section_ino = ino;
ino += *pnt; ino += reclen;
if (cpnt) { if (cpnt)
kfree (cpnt); kfree (cpnt);
cpnt = NULL;
}
i++; 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); brelse(bh);
return 0; 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) void isofs_read_inode(struct inode * inode)
{ {
struct super_block *sb = inode->i_sb;
unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); 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 buffer_head * bh;
struct iso_directory_record * raw_inode; struct iso_directory_record * raw_inode;
unsigned char *pnt = NULL; unsigned char *pnt;
int high_sierra; int volume_seq_no, i;
int block;
int volume_seq_no ;
int i;
block = inode->i_ino >> ISOFS_BUFFER_BITS(inode); bh = bread(inode->i_dev, block, bufsize);
if (!(bh=bread(inode->i_dev,block, bufsize))) { if (!bh) {
printk("unable to read i-node block"); printk(KERN_WARNING "ISOFS: unable to read i-node block\n");
goto fail; goto fail;
} }
pnt = ((unsigned char *) bh->b_data pnt = ((unsigned char *) bh->b_data
+ (inode->i_ino & (bufsize - 1))); + (inode->i_ino & (bufsize - 1)));
raw_inode = ((struct iso_directory_record *) pnt); 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) { if (raw_inode->flags[-high_sierra] & 2) {
inode->i_mode = S_IRUGO | S_IXUGO | S_IFDIR; inode->i_mode = S_IRUGO | S_IXUGO | S_IFDIR;
...@@ -1049,10 +1079,13 @@ void isofs_read_inode(struct inode * inode) ...@@ -1049,10 +1079,13 @@ void isofs_read_inode(struct inode * inode)
easier to give 1 which tells find to easier to give 1 which tells find to
do it the hard way. */ do it the hard way. */
} else { } 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_nlink = 1;
inode->i_mode |= S_IFREG; 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++) for(i=0; i< raw_inode->name_len[0]; i++)
if(raw_inode->name[i]=='.' || raw_inode->name[i]==';') if(raw_inode->name[i]=='.' || raw_inode->name[i]==';')
break; break;
...@@ -1133,13 +1166,15 @@ void isofs_read_inode(struct inode * inode) ...@@ -1133,13 +1166,15 @@ void isofs_read_inode(struct inode * inode)
#ifdef DEBUG #ifdef DEBUG
printk("Inode: %x extent: %x\n",inode->i_ino, inode->u.isofs_i.i_first_extent); printk("Inode: %x extent: %x\n",inode->i_ino, inode->u.isofs_i.i_first_extent);
#endif #endif
brelse(bh);
inode->i_op = NULL;
/* get the volume sequence number */ /* get the volume sequence number */
volume_seq_no = isonum_723 (raw_inode->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. * 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 * We could use the cruft option, but that has multiple purposes, one
...@@ -1152,6 +1187,8 @@ void isofs_read_inode(struct inode * inode) ...@@ -1152,6 +1187,8 @@ void isofs_read_inode(struct inode * inode)
inode->i_sb->u.isofs_sb.s_cruft = 'y'; inode->i_sb->u.isofs_sb.s_cruft = 'y';
} }
/* Install the inode operations vector */
inode->i_op = NULL;
#ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS #ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS
if (inode->i_sb->u.isofs_sb.s_cruft != 'y' && if (inode->i_sb->u.isofs_sb.s_cruft != 'y' &&
(volume_seq_no != 0) && (volume_seq_no != 1)) { (volume_seq_no != 0) && (volume_seq_no != 1)) {
...@@ -1173,6 +1210,7 @@ void isofs_read_inode(struct inode * inode) ...@@ -1173,6 +1210,7 @@ void isofs_read_inode(struct inode * inode)
init_fifo(inode); init_fifo(inode);
} }
return; return;
fail: fail:
/* With a data error we return this information */ /* With a data error we return this information */
inode->i_mtime = inode->i_atime = inode->i_ctime = 0; inode->i_mtime = inode->i_atime = inode->i_ctime = 0;
......
...@@ -54,17 +54,16 @@ ...@@ -54,17 +54,16 @@
{if (buffer) kfree(buffer); \ {if (buffer) kfree(buffer); \
if (cont_extent){ \ if (cont_extent){ \
int block, offset, offset1; \ int block, offset, offset1; \
struct buffer_head * bh; \ struct buffer_head * pbh; \
buffer = kmalloc(cont_size,GFP_KERNEL); \ buffer = kmalloc(cont_size,GFP_KERNEL); \
if (!buffer) goto out; \ if (!buffer) goto out; \
block = cont_extent; \ block = cont_extent; \
offset = cont_offset; \ offset = cont_offset; \
offset1 = 0; \ offset1 = 0; \
if(buffer) { \ pbh = bread(DEV->i_dev, block, ISOFS_BUFFER_SIZE(DEV)); \
bh = bread(DEV->i_dev, block, ISOFS_BUFFER_SIZE(DEV)); \ if(pbh){ \
if(bh){ \ memcpy(buffer + offset1, pbh->b_data + offset, cont_size - offset1); \
memcpy(buffer + offset1, bh->b_data + offset, cont_size - offset1); \ brelse(pbh); \
brelse(bh); \
chr = (unsigned char *) buffer; \ chr = (unsigned char *) buffer; \
len = cont_size; \ len = cont_size; \
cont_extent = 0; \ cont_extent = 0; \
...@@ -72,7 +71,6 @@ ...@@ -72,7 +71,6 @@
cont_offset = 0; \ cont_offset = 0; \
goto LABEL; \ goto LABEL; \
}; \ }; \
} \
printk("Unable to read rock-ridge attributes\n"); \ printk("Unable to read rock-ridge attributes\n"); \
}} }}
...@@ -162,7 +160,6 @@ int get_rock_ridge_filename(struct iso_directory_record * de, ...@@ -162,7 +160,6 @@ int get_rock_ridge_filename(struct iso_directory_record * de,
if (!inode->i_sb->u.isofs_sb.s_rock) return 0; if (!inode->i_sb->u.isofs_sb.s_rock) return 0;
*retname = 0; *retname = 0;
retnamlen = 0;
SETUP_ROCK_RIDGE(de, chr, len); SETUP_ROCK_RIDGE(de, chr, len);
repeat: repeat:
...@@ -364,6 +361,8 @@ int parse_rock_ridge_inode(struct iso_directory_record * de, ...@@ -364,6 +361,8 @@ int parse_rock_ridge_inode(struct iso_directory_record * de,
inode->u.isofs_i.i_first_extent = isonum_733(rr->u.CL.location) << inode->u.isofs_i.i_first_extent = isonum_733(rr->u.CL.location) <<
inode -> i_sb -> u.isofs_sb.s_log_zone_size; inode -> i_sb -> u.isofs_sb.s_log_zone_size;
reloc = iget(inode->i_sb, inode->u.isofs_i.i_first_extent); reloc = iget(inode->i_sb, inode->u.isofs_i.i_first_extent);
if (!reloc)
goto out;
inode->i_mode = reloc->i_mode; inode->i_mode = reloc->i_mode;
inode->i_nlink = reloc->i_nlink; inode->i_nlink = reloc->i_nlink;
inode->i_uid = reloc->i_uid; inode->i_uid = reloc->i_uid;
...@@ -396,8 +395,8 @@ char * get_rock_ridge_symlink(struct inode * inode) ...@@ -396,8 +395,8 @@ char * get_rock_ridge_symlink(struct inode * inode)
unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
unsigned char bufbits = ISOFS_BUFFER_BITS(inode); unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
struct buffer_head * bh; struct buffer_head * bh;
char * rpnt = NULL;
unsigned char * pnt; unsigned char * pnt;
char * rpnt;
struct iso_directory_record * raw_inode; struct iso_directory_record * raw_inode;
CONTINUE_DECLS; CONTINUE_DECLS;
int block; int block;
...@@ -410,13 +409,10 @@ char * get_rock_ridge_symlink(struct inode * inode) ...@@ -410,13 +409,10 @@ char * get_rock_ridge_symlink(struct inode * inode)
if (!inode->i_sb->u.isofs_sb.s_rock) if (!inode->i_sb->u.isofs_sb.s_rock)
panic("Cannot have symlink with high sierra variant of iso filesystem\n"); panic("Cannot have symlink with high sierra variant of iso filesystem\n");
rpnt = 0;
block = inode->i_ino >> bufbits; block = inode->i_ino >> bufbits;
if (!(bh=bread(inode->i_dev,block, bufsize))) { bh = bread(inode->i_dev, block, bufsize);
printk("unable to read i-node block"); if (!bh)
return NULL; goto out_noread;
};
pnt = ((unsigned char *) bh->b_data) + (inode->i_ino & (bufsize - 1)); pnt = ((unsigned char *) bh->b_data) + (inode->i_ino & (bufsize - 1));
...@@ -425,10 +421,8 @@ char * get_rock_ridge_symlink(struct inode * inode) ...@@ -425,10 +421,8 @@ char * get_rock_ridge_symlink(struct inode * inode)
/* /*
* If we go past the end of the buffer, there is some sort of error. * If we go past the end of the buffer, there is some sort of error.
*/ */
if ((inode->i_ino & (bufsize - 1)) + *pnt > bufsize){ if ((inode->i_ino & (bufsize - 1)) + *pnt > bufsize)
printk("symlink spans iso9660 blocks\n"); goto out_bad_span;
return NULL;
};
/* Now test for possible Rock Ridge extensions which will override some of /* Now test for possible Rock Ridge extensions which will override some of
these numbers in the inode structure. */ these numbers in the inode structure. */
...@@ -511,16 +505,23 @@ char * get_rock_ridge_symlink(struct inode * inode) ...@@ -511,16 +505,23 @@ char * get_rock_ridge_symlink(struct inode * inode)
}; };
}; };
MAYBE_CONTINUE(repeat,inode); MAYBE_CONTINUE(repeat,inode);
brelse(bh);
out_freebh:
brelse(bh);
return rpnt; return rpnt;
out:
if(buffer) kfree(buffer);
return 0;
}
/* 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;
}
...@@ -281,15 +281,16 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name) ...@@ -281,15 +281,16 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name)
} }
/* /*
* The bitmask for a follow event: normal * The bitmask for a lookup event:
* follow, and follow requires a directory * - follow links at the end
* entry due to a slash ('/') after the * - require a directory
* name, and whether to continue to parse * - ending slashes ok even for nonexistent files
* the name.. * - internal "there are more path compnents" flag
*/ */
#define FOLLOW_LINK (1) #define LOOKUP_FOLLOW (1)
#define FOLLOW_DIRECTORY (2) #define LOOKUP_DIRECTORY (2)
#define FOLLOW_CONTINUE (4) #define LOOKUP_SLASHOK (4)
#define LOOKUP_CONTINUE (8)
static struct dentry * do_follow_link(struct dentry *base, struct dentry *dentry, unsigned int follow) static struct dentry * do_follow_link(struct dentry *base, struct dentry *dentry, unsigned int follow)
{ {
...@@ -331,7 +332,7 @@ static inline struct dentry * follow_mount(struct dentry * dentry) ...@@ -331,7 +332,7 @@ static inline struct dentry * follow_mount(struct dentry * dentry)
* This is the basic name resolution function, turning a pathname * This is the basic name resolution function, turning a pathname
* into the final dentry. * into the final dentry.
*/ */
struct dentry * lookup_dentry(const char * name, struct dentry * base, unsigned int follow_link) struct dentry * lookup_dentry(const char * name, struct dentry * base, unsigned int lookup_flags)
{ {
struct dentry * dentry; struct dentry * dentry;
struct inode *inode; struct inode *inode;
...@@ -351,14 +352,14 @@ struct dentry * lookup_dentry(const char * name, struct dentry * base, unsigned ...@@ -351,14 +352,14 @@ struct dentry * lookup_dentry(const char * name, struct dentry * base, unsigned
goto return_base; goto return_base;
inode = base->d_inode; inode = base->d_inode;
follow_link &= FOLLOW_LINK | FOLLOW_DIRECTORY; lookup_flags &= LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_SLASHOK;
/* At this point we know we have a real path component. */ /* At this point we know we have a real path component. */
for(;;) { for(;;) {
int err; int err;
unsigned long hash; unsigned long hash;
struct qstr this; struct qstr this;
unsigned int follow; unsigned int flags;
unsigned int c; unsigned int c;
err = permission(inode, MAY_EXEC); err = permission(inode, MAY_EXEC);
...@@ -379,16 +380,16 @@ struct dentry * lookup_dentry(const char * name, struct dentry * base, unsigned ...@@ -379,16 +380,16 @@ struct dentry * lookup_dentry(const char * name, struct dentry * base, unsigned
this.hash = end_name_hash(hash); this.hash = end_name_hash(hash);
/* remove trailing slashes? */ /* remove trailing slashes? */
follow = follow_link; flags = lookup_flags;
if (c) { if (c) {
char tmp; char tmp;
follow |= FOLLOW_DIRECTORY; flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
do { do {
tmp = *++name; tmp = *++name;
} while (tmp == '/'); } while (tmp == '/');
if (tmp) if (tmp)
follow |= FOLLOW_CONTINUE; flags |= LOOKUP_CONTINUE;
} }
/* /*
...@@ -418,26 +419,47 @@ struct dentry * lookup_dentry(const char * name, struct dentry * base, unsigned ...@@ -418,26 +419,47 @@ struct dentry * lookup_dentry(const char * name, struct dentry * base, unsigned
/* Check mountpoints.. */ /* Check mountpoints.. */
dentry = follow_mount(dentry); dentry = follow_mount(dentry);
if (!follow) if (!(flags & LOOKUP_FOLLOW))
break; break;
base = do_follow_link(base, dentry, follow); base = do_follow_link(base, dentry, flags);
if (IS_ERR(base)) if (IS_ERR(base))
goto return_base; goto return_base;
dentry = ERR_PTR(-ENOENT);
inode = base->d_inode; inode = base->d_inode;
if (follow & FOLLOW_DIRECTORY) { if (flags & LOOKUP_DIRECTORY) {
if (!inode) if (!inode)
break; goto no_inode;
dentry = ERR_PTR(-ENOTDIR); dentry = ERR_PTR(-ENOTDIR);
if (!inode->i_op || !inode->i_op->lookup) if (!inode->i_op || !inode->i_op->lookup)
break; break;
if (follow & FOLLOW_CONTINUE) if (flags & LOOKUP_CONTINUE)
continue; continue;
} }
return_base: return_base:
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); dput(base);
return dentry; return dentry;
...@@ -453,7 +475,7 @@ struct dentry * lookup_dentry(const char * name, struct dentry * base, unsigned ...@@ -453,7 +475,7 @@ struct dentry * lookup_dentry(const char * name, struct dentry * base, unsigned
* namei exists in two versions: namei/lnamei. The only difference is * namei exists in two versions: namei/lnamei. The only difference is
* that namei follows links, while lnamei does not. * that namei follows links, while lnamei does not.
*/ */
struct dentry * __namei(const char *pathname, unsigned int follow_link) struct dentry * __namei(const char *pathname, unsigned int lookup_flags)
{ {
char *name; char *name;
struct dentry *dentry; struct dentry *dentry;
...@@ -461,7 +483,7 @@ struct dentry * __namei(const char *pathname, unsigned int follow_link) ...@@ -461,7 +483,7 @@ struct dentry * __namei(const char *pathname, unsigned int follow_link)
name = getname(pathname); name = getname(pathname);
dentry = (struct dentry *) name; dentry = (struct dentry *) name;
if (!IS_ERR(name)) { if (!IS_ERR(name)) {
dentry = lookup_dentry(name, NULL, follow_link); dentry = lookup_dentry(name, NULL, lookup_flags);
putname(name); putname(name);
if (!IS_ERR(dentry)) { if (!IS_ERR(dentry)) {
if (!dentry->d_inode) { if (!dentry->d_inode) {
...@@ -659,7 +681,7 @@ struct dentry * do_mknod(const char * filename, int mode, dev_t dev) ...@@ -659,7 +681,7 @@ struct dentry * do_mknod(const char * filename, int mode, dev_t dev)
struct dentry *dentry, *retval; struct dentry *dentry, *retval;
mode &= ~current->fs->umask; mode &= ~current->fs->umask;
dentry = lookup_dentry(filename, NULL, 1); dentry = lookup_dentry(filename, NULL, LOOKUP_FOLLOW);
if (IS_ERR(dentry)) if (IS_ERR(dentry))
return dentry; return dentry;
...@@ -743,7 +765,7 @@ static inline int do_mkdir(const char * pathname, int mode) ...@@ -743,7 +765,7 @@ static inline int do_mkdir(const char * pathname, int mode)
struct dentry *dir; struct dentry *dir;
struct dentry *dentry; struct dentry *dentry;
dentry = lookup_dentry(pathname, NULL, 0); dentry = lookup_dentry(pathname, NULL, LOOKUP_SLASHOK);
error = PTR_ERR(dentry); error = PTR_ERR(dentry);
if (IS_ERR(dentry)) if (IS_ERR(dentry))
goto exit; goto exit;
...@@ -1150,7 +1172,16 @@ static inline int do_rename(const char * oldname, const char * newname) ...@@ -1150,7 +1172,16 @@ static inline int do_rename(const char * oldname, const char * newname)
if (IS_ERR(old_dentry)) if (IS_ERR(old_dentry))
goto exit; 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); error = PTR_ERR(new_dentry);
if (IS_ERR(new_dentry)) if (IS_ERR(new_dentry))
...@@ -1161,10 +1192,6 @@ static inline int do_rename(const char * oldname, const char * newname) ...@@ -1161,10 +1192,6 @@ static inline int do_rename(const char * oldname, const char * newname)
double_lock(new_dir, old_dir); 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); error = permission(old_dir->d_inode,MAY_WRITE | MAY_EXEC);
if (error) if (error)
goto exit_lock; goto exit_lock;
......
...@@ -416,23 +416,16 @@ parent->d_name.name, dentry->d_name.name); ...@@ -416,23 +416,16 @@ parent->d_name.name, dentry->d_name.name);
*/ */
error = nfs_proc_lookup(NFS_DSERVER(parent), NFS_FH(parent), error = nfs_proc_lookup(NFS_DSERVER(parent), NFS_FH(parent),
dentry->d_name.name, &fhandle, &fattr); dentry->d_name.name, &fhandle, &fattr);
if (error) { if (error)
printk("nfs_lookup_revalidate: error=%d\n", error);
goto out_bad; goto out_bad;
}
/* Inode number matches? */ /* Inode number matches? */
if (fattr.fileid != inode->i_ino) { 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);
goto out_bad; goto out_bad;
}
/* Filehandle matches? */ /* Filehandle matches? */
if (memcmp(dentry->d_fsdata, &fhandle, sizeof(struct nfs_fh))) { 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);
goto out_bad; goto out_bad;
}
out_valid: out_valid:
return 1; return 1;
......
...@@ -322,18 +322,20 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent) ...@@ -322,18 +322,20 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
goto out_shutdown; goto out_shutdown;
out_no_iod: out_no_iod:
printk("NFS: couldn't start rpciod!\n"); printk(KERN_WARNING "NFS: couldn't start rpciod!\n");
out_shutdown: out_shutdown:
rpc_shutdown_client(server->client); rpc_shutdown_client(server->client);
goto out_unlock; goto out_free_host;
out_no_client: out_no_client:
printk("NFS: cannot create RPC client.\n"); printk(KERN_WARNING "NFS: cannot create RPC client.\n");
xprt_destroy(xprt); xprt_destroy(xprt);
goto out_unlock; goto out_free_host;
out_no_xprt: 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); kfree(server->hostname);
out_unlock: out_unlock:
unlock_super(sb); unlock_super(sb);
...@@ -393,9 +395,10 @@ void nfs_free_dentries(struct inode *inode) ...@@ -393,9 +395,10 @@ void nfs_free_dentries(struct inode *inode)
tmp = head; tmp = head;
while ((tmp = tmp->next) != head) { while ((tmp = tmp->next) != head) {
struct dentry *dentry = list_entry(tmp, struct dentry, d_alias); 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) { 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); dget(dentry);
d_drop(dentry); d_drop(dentry);
dput(dentry); dput(dentry);
......
...@@ -215,7 +215,7 @@ int mem_mmap(struct file * file, struct vm_area_struct * vma) ...@@ -215,7 +215,7 @@ int mem_mmap(struct file * file, struct vm_area_struct * vma)
pgd_t *src_dir, *dest_dir; pgd_t *src_dir, *dest_dir;
pmd_t *src_middle, *dest_middle; pmd_t *src_middle, *dest_middle;
pte_t *src_table, *dest_table; pte_t *src_table, *dest_table;
unsigned long stmp, dtmp; unsigned long stmp, dtmp, mapnr;
struct vm_area_struct *src_vma = NULL; struct vm_area_struct *src_vma = NULL;
struct inode *inode = file->f_dentry->d_inode; struct inode *inode = file->f_dentry->d_inode;
...@@ -296,6 +296,8 @@ int mem_mmap(struct file * file, struct vm_area_struct * vma) ...@@ -296,6 +296,8 @@ int mem_mmap(struct file * file, struct vm_area_struct * vma)
set_pte(src_table, pte_mkdirty(*src_table)); set_pte(src_table, pte_mkdirty(*src_table));
set_pte(dest_table, *src_table); set_pte(dest_table, *src_table);
mapnr = MAP_NR(pte_page(*src_table));
if (mapnr < max_mapnr)
atomic_inc(&mem_map[MAP_NR(pte_page(*src_table))].count); atomic_inc(&mem_map[MAP_NR(pte_page(*src_table))].count);
stmp += PAGE_SIZE; stmp += PAGE_SIZE;
......
...@@ -868,17 +868,19 @@ int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const cha ...@@ -868,17 +868,19 @@ int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const cha
struct vfsmount *vfsmnt; struct vfsmount *vfsmnt;
int error; int error;
down(&mount_sem);
error = -EACCES; error = -EACCES;
if (!(flags & MS_RDONLY) && dev && is_read_only(dev)) if (!(flags & MS_RDONLY) && dev && is_read_only(dev))
goto out; goto out;
/*flags |= MS_RDONLY;*/
/*
* Do the lookup first to force automounting.
*/
dir_d = namei(dir_name); dir_d = namei(dir_name);
error = PTR_ERR(dir_d); error = PTR_ERR(dir_d);
if (IS_ERR(dir_d)) if (IS_ERR(dir_d))
goto out; goto out;
down(&mount_sem);
error = -ENOTDIR; error = -ENOTDIR;
if (!S_ISDIR(dir_d->d_inode->i_mode)) if (!S_ISDIR(dir_d->d_inode->i_mode))
goto dput_and_out; goto dput_and_out;
...@@ -906,18 +908,16 @@ int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const cha ...@@ -906,18 +908,16 @@ int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const cha
error = -ENOMEM; error = -ENOMEM;
vfsmnt = add_vfsmnt(sb, dev_name, dir_name); vfsmnt = add_vfsmnt(sb, dev_name, dir_name);
if (!vfsmnt) if (vfsmnt) {
goto dput_and_out; d_mount(dget(dir_d), sb->s_root);
d_mount(dir_d, sb->s_root); error = 0;
error = 0; /* we don't dput(dir_d) - see umount */ }
out:
up(&mount_sem);
return error;
dput_and_out: dput_and_out:
dput(dir_d); dput(dir_d);
goto out; up(&mount_sem);
out:
return error;
} }
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#define UMSDOS_SPECIAL_DIRFPOS 3 #define UMSDOS_SPECIAL_DIRFPOS 3
extern struct dentry *saved_root;
extern struct inode *pseudo_root; extern struct inode *pseudo_root;
/* #define UMSDOS_DEBUG_VERBOSE 1 */ /* #define UMSDOS_DEBUG_VERBOSE 1 */
...@@ -53,42 +54,6 @@ static struct dentry_operations umsdos_dentry_operations = ...@@ -53,42 +54,6 @@ static struct dentry_operations umsdos_dentry_operations =
NULL, 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. * So grep * doesn't complain in the presence of directories.
...@@ -203,9 +168,11 @@ Printk (("umsdos_readdir_x: what UMSDOS_SPECIAL_DIRFPOS /mn/?\n")); ...@@ -203,9 +168,11 @@ Printk (("umsdos_readdir_x: what UMSDOS_SPECIAL_DIRFPOS /mn/?\n"));
ret = PTR_ERR(demd); ret = PTR_ERR(demd);
if (IS_ERR(demd)) if (IS_ERR(demd))
goto out_end; goto out_end;
ret = 0; ret = -EIO;
if (!demd->d_inode) { 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; goto out_dput;
} }
...@@ -404,18 +371,17 @@ static int UMSDOS_readdir (struct file *filp, void *dirbuf, filldir_t filldir) ...@@ -404,18 +371,17 @@ static int UMSDOS_readdir (struct file *filp, void *dirbuf, filldir_t filldir)
* does this automatically. * does this automatically.
*/ */
void umsdos_lookup_patch (struct inode *dir, struct inode *inode, void umsdos_lookup_patch_new(struct dentry *dentry, struct umsdos_info *info)
struct umsdos_dirent *entry, off_t emd_pos)
{ {
if (inode->i_sb != dir->i_sb) struct inode *inode = dentry->d_inode;
goto out; struct umsdos_dirent *entry = &info->entry;
if (umsdos_isinit (inode))
goto out;
if (S_ISDIR (inode->i_mode)) /*
umsdos_lockcreate (inode); * This part of the initialization depends only on i_patched.
if (umsdos_isinit (inode)) */
goto out_unlock; if (inode->u.umsdos_i.i_patched)
goto out;
inode->u.umsdos_i.i_patched = 1;
if (S_ISREG (entry->mode)) if (S_ISREG (entry->mode))
entry->mtime = inode->i_mtime; entry->mtime = inode->i_mtime;
...@@ -444,146 +410,14 @@ void umsdos_lookup_patch (struct inode *dir, struct inode *inode, ...@@ -444,146 +410,14 @@ void umsdos_lookup_patch (struct inode *dir, struct inode *inode,
"UMSDOS: lookup_patch entry->nlink < 1 ???\n"); "UMSDOS: lookup_patch entry->nlink < 1 ???\n");
} }
} }
umsdos_patch_inode (inode, dir, emd_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. * The mode may have changed, so patch the inode again.
* Also umsdos_readdir_x won't show /linux anyway
*/ */
memcpy (entry->name, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN + 1); umsdos_patch_dentry_inode(dentry, info->f_pos);
entry->name_len = UMSDOS_PSDROOT_LEN; umsdos_set_dirinfo_new(dentry, info->f_pos);
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: out:
return ret; return;
} }
...@@ -627,8 +461,6 @@ int umsdos_is_pseudodos (struct inode *dir, struct dentry *dentry) ...@@ -627,8 +461,6 @@ 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)
{ {
const char *name = dentry->d_name.name;
int len = dentry->d_name.len;
struct dentry *dret = NULL; struct dentry *dret = NULL;
struct inode *inode; struct inode *inode;
int ret = -ENOENT; int ret = -ENOENT;
...@@ -640,28 +472,13 @@ dentry->d_parent->d_name.name, dentry->d_name.name); ...@@ -640,28 +472,13 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
#endif #endif
umsdos_startlookup (dir); 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)) { if (umsdos_is_pseudodos (dir, dentry)) {
/* #Specification: pseudo root / lookup(DOS) /* #Specification: pseudo root / lookup(DOS)
* A lookup of DOS in the pseudo root will always succeed * A lookup of DOS in the pseudo root will always succeed
* and return the inode of the real root. * and return the inode of the real root.
*/ */
inode = iget(dir->i_sb, UMSDOS_ROOT_INO); inode = saved_root->d_inode;
if (inode)
goto out_add; goto out_add;
ret = -ENOMEM;
goto out;
} }
ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info); ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
...@@ -693,7 +510,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name, ret); ...@@ -693,7 +510,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name, ret);
inode = dret->d_inode; inode = dret->d_inode;
if (!inode) if (!inode)
goto out_remove; goto out_remove;
umsdos_lookup_patch_new(dret, &info.entry, info.f_pos); umsdos_lookup_patch_new(dret, &info);
#ifdef UMSDOS_DEBUG_VERBOSE #ifdef UMSDOS_DEBUG_VERBOSE
printk("umsdos_lookup_x: found %s/%s, ino=%ld\n", 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); dret->d_parent->d_name.name, dret->d_name.name, dret->d_inode->i_ino);
...@@ -726,6 +543,7 @@ dret->d_parent->d_name.name, dret->d_name.name); ...@@ -726,6 +543,7 @@ dret->d_parent->d_name.name, dret->d_name.name);
* mode. * mode.
*/ */
printk(KERN_WARNING "umsdos_lookup_x: untested, inode == Pseudo_root\n"); printk(KERN_WARNING "umsdos_lookup_x: untested, inode == Pseudo_root\n");
ret = -ENOENT;
goto out_dput; goto out_dput;
} }
......
...@@ -189,7 +189,9 @@ ssize_t umsdos_emd_dir_read (struct file *filp, char *buf, size_t count) ...@@ -189,7 +189,9 @@ ssize_t umsdos_emd_dir_read (struct file *filp, char *buf, size_t count)
/* /*
* 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) struct dentry *umsdos_get_emd_dentry(struct dentry *parent)
{ {
...@@ -202,6 +204,8 @@ struct dentry *umsdos_get_emd_dentry(struct dentry *parent) ...@@ -202,6 +204,8 @@ struct dentry *umsdos_get_emd_dentry(struct dentry *parent)
/* /*
* Check whether a directory has an EMD file. * 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) int umsdos_have_emd(struct dentry *dir)
{ {
...@@ -219,11 +223,12 @@ int umsdos_have_emd(struct dentry *dir) ...@@ -219,11 +223,12 @@ int umsdos_have_emd(struct dentry *dir)
/* /*
* Create the EMD file for a directory if it doesn't * Create the EMD file for a directory if it doesn't
* already exist. Returns 0 or an error code. * 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) int umsdos_make_emd(struct dentry *parent)
{ {
struct dentry *demd = umsdos_get_emd_dentry(parent); struct dentry *demd = umsdos_get_emd_dentry(parent);
struct inode *inode;
int err = PTR_ERR(demd); int err = PTR_ERR(demd);
if (IS_ERR(demd)) { if (IS_ERR(demd)) {
...@@ -234,8 +239,7 @@ int umsdos_make_emd(struct dentry *parent) ...@@ -234,8 +239,7 @@ int umsdos_make_emd(struct dentry *parent)
/* already created? */ /* already created? */
err = 0; err = 0;
inode = demd->d_inode; if (demd->d_inode)
if (inode)
goto out_set; goto out_set;
Printk(("umsdos_make_emd: creating EMD %s/%s\n", Printk(("umsdos_make_emd: creating EMD %s/%s\n",
...@@ -244,15 +248,12 @@ parent->d_name.name, demd->d_name.name)); ...@@ -244,15 +248,12 @@ parent->d_name.name, demd->d_name.name));
err = msdos_create(parent->d_inode, demd, S_IFREG | 0777); err = msdos_create(parent->d_inode, demd, S_IFREG | 0777);
if (err) { if (err) {
printk (KERN_WARNING 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); parent->d_name.name, demd->d_name.name, err);
goto out_dput; goto out_dput;
} }
inode = demd->d_inode;
out_set: out_set:
parent->d_inode->u.umsdos_i.i_emd_dir = inode->i_ino; parent->d_inode->u.umsdos_i.i_emd_dir = demd->d_inode->i_ino;
/* Disable UMSDOS_notify_change() for EMD file */
inode->u.umsdos_i.i_emd_owner = 0xffffffff;
out_dput: out_dput:
dput(demd); dput(demd);
...@@ -261,92 +262,6 @@ parent->d_name.name, demd->d_name.name)); ...@@ -261,92 +262,6 @@ parent->d_name.name, demd->d_name.name));
} }
/*
* 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. * Read an entry from the EMD file.
* Support variable length record. * Support variable length record.
...@@ -387,6 +302,8 @@ Printk (("umsdos_emd_dir_readentry /mn/: returning len=%d,name=%.*s\n", ...@@ -387,6 +302,8 @@ Printk (("umsdos_emd_dir_readentry /mn/: returning len=%d,name=%.*s\n",
/* /*
* Write an entry in the EMD file. * Write an entry in the EMD file.
* Return 0 if OK, -EIO if some error. * 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, static int umsdos_writeentry (struct dentry *parent, struct umsdos_info *info,
int free_entry) int free_entry)
...@@ -405,8 +322,9 @@ static int umsdos_writeentry (struct dentry *parent, struct umsdos_info *info, ...@@ -405,8 +322,9 @@ static int umsdos_writeentry (struct dentry *parent, struct umsdos_info *info,
/* make sure there's an EMD file */ /* make sure there's an EMD file */
ret = -EIO; ret = -EIO;
if (!emd_dentry->d_inode) { if (!emd_dentry->d_inode) {
printk("umsdos_writeentry: no EMD file in %s/%s\n", printk(KERN_WARNING
parent->d_parent->d_name.name, parent->d_name.name); "umsdos_writeentry: no EMD file in %s/%s\n",
parent->d_parent->d_name.name, parent->d_name.name);
goto out_dput; goto out_dput;
} }
...@@ -468,6 +386,8 @@ struct find_buffer { ...@@ -468,6 +386,8 @@ struct find_buffer {
* Unread bytes are simply moved to the beginning. * Unread bytes are simply moved to the beginning.
* *
* Return -ENOENT if EOF, 0 if OK, a negative error code if any problem. * 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) static int umsdos_fillbuf (struct find_buffer *buf)
...@@ -518,6 +438,7 @@ static int umsdos_fillbuf (struct find_buffer *buf) ...@@ -518,6 +438,7 @@ static int umsdos_fillbuf (struct find_buffer *buf)
* All this to say that umsdos_writeentry must be called after this * All this to say that umsdos_writeentry must be called after this
* function since it relies on the f_pos field of info. * 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 /* #Specification: EMD file structure
* The EMD file uses a fairly simple layout. It is made of records * The EMD file uses a fairly simple layout. It is made of records
......
...@@ -23,35 +23,11 @@ extern struct dentry_operations umsdos_dentry_operations; ...@@ -23,35 +23,11 @@ extern struct dentry_operations umsdos_dentry_operations;
extern struct inode_operations umsdos_rdir_inode_operations; 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 */ struct inode *pseudo_root = NULL; /* Useful to simulate the pseudo DOS */
/* directory. See UMSDOS_readdir_x() */ /* directory. See UMSDOS_readdir_x() */
static struct dentry *check_pseudo_root(struct super_block *);
/*
* 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;
}
/* /*
...@@ -70,61 +46,6 @@ void fill_new_filp (struct file *filp, struct dentry *dentry) ...@@ -70,61 +46,6 @@ void fill_new_filp (struct file *filp, struct dentry *dentry)
} }
/*
* 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) void UMSDOS_put_inode (struct inode *inode)
{ {
...@@ -146,18 +67,23 @@ void UMSDOS_put_inode (struct inode *inode) ...@@ -146,18 +67,23 @@ void UMSDOS_put_inode (struct inode *inode)
void UMSDOS_put_super (struct super_block *sb) void UMSDOS_put_super (struct super_block *sb)
{ {
Printk ((KERN_DEBUG "UMSDOS_put_super: entering\n")); 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); msdos_put_super (sb);
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
} }
/* /*
* Complete the setup of an directory dentry. * Complete the setup of a directory dentry based on its
* First, it completes the function pointers, then * EMD/non-EMD status. If it has an EMD, then plug the
* it locates the EMD file. If the EMD is there, then plug the
* umsdos function table. If not, use the msdos one. * umsdos function table. If not, use the msdos one.
*
* {i,d}_counts are untouched by this function.
*/ */
void umsdos_setup_dir(struct dentry *dir) void umsdos_setup_dir(struct dentry *dir)
{ {
...@@ -176,40 +102,6 @@ dir->d_parent->d_name.name, dir->d_name.name)); ...@@ -176,40 +102,6 @@ dir->d_parent->d_name.name, dir->d_name.name));
} }
} }
/*
* 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 * Add some info into an inode so it can find its owner quickly
...@@ -224,34 +116,11 @@ void umsdos_set_dirinfo_new (struct dentry *dentry, off_t f_pos) ...@@ -224,34 +116,11 @@ void umsdos_set_dirinfo_new (struct dentry *dentry, off_t f_pos)
/* now check the EMD file */ /* now check the EMD file */
demd = umsdos_get_emd_dentry(dentry->d_parent); demd = umsdos_get_emd_dentry(dentry->d_parent);
if (IS_ERR(demd)) { if (!IS_ERR(demd)) {
goto out; if (demd->d_inode)
}
if (demd->d_inode) {
inode->u.umsdos_i.i_emd_owner = demd->d_inode->i_ino; 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; return;
} }
...@@ -262,28 +131,12 @@ void umsdos_set_dirinfo (struct inode *inode, struct inode *dir, off_t f_pos) ...@@ -262,28 +131,12 @@ void umsdos_set_dirinfo (struct inode *inode, struct inode *dir, off_t f_pos)
*/ */
int umsdos_isinit (struct inode *inode) 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. * 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 /* #Specification: inode / umsdos info
* The first time an inode is seen (inode->i_count == 1), * The first time an inode is seen (inode->i_count == 1),
...@@ -291,88 +144,45 @@ int umsdos_isinit (struct inode *inode) ...@@ -291,88 +144,45 @@ int umsdos_isinit (struct inode *inode)
* is tagged to this inode. It allows operations such as * is tagged to this inode. It allows operations such as
* notify_change to be handled. * 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", struct inode *inode = dentry->d_inode;
inode->i_ino));
if (umsdos_isinit (inode)) Printk (("umsdos_patch_dentry_inode: inode=%lu\n", inode->i_ino));
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; inode->u.umsdos_i.i_emd_dir = 0;
if (S_ISREG (inode->i_mode)) { if (S_ISREG (inode->i_mode)) {
if (MSDOS_SB (inode->i_sb)->cvf_format) { if (MSDOS_SB (inode->i_sb)->cvf_format) {
if (MSDOS_SB (inode->i_sb)->cvf_format->flags & CVF_USE_READPAGE) { 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; inode->i_op = &umsdos_file_inode_operations_readpage;
} else { } else {
Printk ((KERN_DEBUG "umsdos_patch_inode: umsdos_file_inode_ops_no_bmap\n"));
inode->i_op = &umsdos_file_inode_operations_no_bmap; inode->i_op = &umsdos_file_inode_operations_no_bmap;
} }
} else { } else {
if (inode->i_op->bmap != NULL) { if (inode->i_op->bmap != NULL) {
Printk ((KERN_DEBUG "umsdos_patch_inode: umsdos_file_inode_ops\n"));
inode->i_op = &umsdos_file_inode_operations; inode->i_op = &umsdos_file_inode_operations;
} else { } else {
Printk ((KERN_DEBUG "umsdos_patch_inode: umsdos_file_inode_ops_no_bmap\n"));
inode->i_op = &umsdos_file_inode_operations_no_bmap; inode->i_op = &umsdos_file_inode_operations_no_bmap;
} }
} }
} else if (S_ISDIR (inode->i_mode)) { } else if (S_ISDIR (inode->i_mode)) {
if (dir != NULL) { umsdos_setup_dir(dentry);
umsdos_setup_dir_inode (inode);
}
} else if (S_ISLNK (inode->i_mode)) { } 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; inode->i_op = &umsdos_symlink_inode_operations;
} else if (S_ISCHR (inode->i_mode)) { } else if (S_ISCHR (inode->i_mode)) {
Printk ((KERN_DEBUG "umsdos_patch_inode: chrdev_inode_ops\n"));
inode->i_op = &chrdev_inode_operations; inode->i_op = &chrdev_inode_operations;
} else if (S_ISBLK (inode->i_mode)) { } else if (S_ISBLK (inode->i_mode)) {
Printk ((KERN_DEBUG "umsdos_patch_inode: blkdev_inode_ops\n"));
inode->i_op = &blkdev_inode_operations; inode->i_op = &blkdev_inode_operations;
} else if (S_ISFIFO (inode->i_mode)) { } else if (S_ISFIFO (inode->i_mode)) {
Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: uhm, init_fifo\n"));
init_fifo (inode); 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,39 +192,42 @@ void umsdos_patch_dentry_inode(struct dentry *dentry, off_t f_pos) ...@@ -382,39 +192,42 @@ void umsdos_patch_dentry_inode(struct dentry *dentry, off_t f_pos)
/* #Specification: Inode / post initialisation /* #Specification: Inode / post initialisation
* To completely initialise an inode, we need access to the owner * To completely initialise an inode, we need access to the owner
* directory, so we can locate more info in the EMD file. This is * 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. * 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 * New inodes are obtained by the lookup and create routines, and
* problem. It is possible that two or more process use the * each of these must ensure that the inode gets patched.
* 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.
*/ */
void UMSDOS_read_inode (struct inode *inode) void UMSDOS_read_inode (struct inode *inode)
{ {
PRINTK ((KERN_DEBUG "UMSDOS_read_inode %p ino = %lu ", PRINTK ((KERN_DEBUG "UMSDOS_read_inode %p ino = %lu ",
inode, inode->i_ino)); inode, inode->i_ino));
msdos_read_inode (inode); 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 ... */ /* inode needs patching */
umsdos_patch_inode (inode, NULL, 0); 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) 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 inode *inode = dentry->d_inode;
struct dentry *demd; struct dentry *demd;
...@@ -433,16 +246,15 @@ dentry->d_parent->d_name.name, dentry->d_name.name, ret); ...@@ -433,16 +246,15 @@ dentry->d_parent->d_name.name, dentry->d_name.name, ret);
} }
if (inode->i_nlink == 0) if (inode->i_nlink == 0)
goto out_nolink; goto out;
if (inode->i_ino == UMSDOS_ROOT_INO) if (inode->i_ino == UMSDOS_ROOT_INO)
goto out_nolink; goto out;
/* get the EMD file dentry */ /* get the EMD file dentry */
demd = umsdos_get_emd_dentry(dentry->d_parent); demd = umsdos_get_emd_dentry(dentry->d_parent);
ret = PTR_ERR(demd); ret = PTR_ERR(demd);
if (IS_ERR(demd)) if (IS_ERR(demd))
goto out_nolink; goto out;
ret = -EPERM; ret = -EPERM;
if (!demd->d_inode) { if (!demd->d_inode) {
printk(KERN_WARNING printk(KERN_WARNING
...@@ -509,10 +321,9 @@ dentry->d_parent->d_name.name, dentry->d_name.name, entry.nlink, ret); ...@@ -509,10 +321,9 @@ dentry->d_parent->d_name.name, dentry->d_name.name, entry.nlink, ret);
out_dput: out_dput:
dput(demd); dput(demd);
out_nolink: out:
if (ret == 0) if (ret == 0)
inode_setattr (inode, attr); inode_setattr (inode, attr);
out:
return ret; return ret;
} }
...@@ -562,7 +373,7 @@ struct super_block *UMSDOS_read_super (struct super_block *sb, void *data, ...@@ -562,7 +373,7 @@ struct super_block *UMSDOS_read_super (struct super_block *sb, void *data,
int silent) int silent)
{ {
struct super_block *res; struct super_block *res;
struct inode *pseudo = NULL; struct dentry *new_root;
MOD_INC_USE_COUNT; MOD_INC_USE_COUNT;
MSDOS_SB(sb)->options.isvfat = 0; MSDOS_SB(sb)->options.isvfat = 0;
...@@ -583,14 +394,19 @@ struct super_block *UMSDOS_read_super (struct super_block *sb, void *data, ...@@ -583,14 +394,19 @@ struct super_block *UMSDOS_read_super (struct super_block *sb, void *data,
/* install our dentry operations ... */ /* install our dentry operations ... */
sb->s_root->d_op = &umsdos_dentry_operations; sb->s_root->d_op = &umsdos_dentry_operations;
pseudo = sb->s_root->d_inode; umsdos_patch_dentry_inode(sb->s_root, 0);
umsdos_setup_dir(sb->s_root);
/* Check whether to change to the /linux root */
#if 0 new_root = check_pseudo_root(sb);
if (pseudo) { if (new_root) {
pseudo_root_stuff(); 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 d_count is not 1, mount will fail with -EBUSY! */
if (sb->s_root->d_count > 1) { if (sb->s_root->d_count > 1) {
...@@ -606,78 +422,50 @@ struct super_block *UMSDOS_read_super (struct super_block *sb, void *data, ...@@ -606,78 +422,50 @@ struct super_block *UMSDOS_read_super (struct super_block *sb, void *data,
} }
/* /*
* FIXME URGENT: * Check for an alternate root if we're the root device.
* disable pseudo root-for the moment of testing.
* re-enable this before release !
*/ */
#if 0 static struct dentry *check_pseudo_root(struct super_block *sb)
void pseudo_root_stuff(void)
{ {
struct dentry *root, *etc, *etc_rc, *sbin, *init = NULL; struct dentry *root, *init;
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);
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); * Check whether we're mounted as the root device.
* If so, this should be the only superblock.
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;
}
/* 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);
*/ */
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);
/* 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;
/* Alternate root not found ... */
out_dput:
dput(root);
out_noroot:
return NULL;
} }
#endif
static struct file_system_type umsdos_fs_type = static struct file_system_type umsdos_fs_type =
......
...@@ -262,7 +262,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name, ret)); ...@@ -262,7 +262,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name, ret));
* is in the dos_dirent.name field and the destination * is in the dos_dirent.name field and the destination
* is in umsdos_dirent.name field. * 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. * name before syncing it back in the EMD.
*/ */
old_dentry = umsdos_lookup_dentry (dentry, old_dentry = umsdos_lookup_dentry (dentry,
...@@ -282,7 +282,6 @@ new_dentry->d_parent->d_name.name, new_dentry->d_name.name); ...@@ -282,7 +282,6 @@ new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
ret = msdos_rename (dir, old_dentry, dir, new_dentry); ret = msdos_rename (dir, old_dentry, dir, new_dentry);
dput(new_dentry); dput(new_dentry);
} }
d_drop(old_dentry);
dput(old_dentry); dput(old_dentry);
goto out; goto out;
} }
...@@ -306,6 +305,11 @@ new_dentry->d_parent->d_name.name, new_dentry->d_name.name); ...@@ -306,6 +305,11 @@ new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
data.umsdos_dirent.name_len, &info); data.umsdos_dirent.name_len, &info);
ret = umsdos_delentry (dentry, &info, ret = umsdos_delentry (dentry, &info,
S_ISDIR (data.umsdos_dirent.mode)); 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; goto out;
} }
else if (cmd == UMSDOS_UNLINK_DOS) { else if (cmd == UMSDOS_UNLINK_DOS) {
...@@ -324,9 +328,11 @@ new_dentry->d_parent->d_name.name, new_dentry->d_name.name); ...@@ -324,9 +328,11 @@ new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
if (IS_ERR(temp)) if (IS_ERR(temp))
goto out; goto out;
ret = -ENOENT; ret = -ENOENT;
if (temp->d_inode) if (temp->d_inode) {
ret = -EISDIR;
if (!S_ISDIR(temp->d_inode->i_mode))
ret = msdos_unlink (dir, temp); ret = msdos_unlink (dir, temp);
d_drop(temp); }
dput (temp); dput (temp);
goto out; goto out;
} }
...@@ -346,9 +352,11 @@ new_dentry->d_parent->d_name.name, new_dentry->d_name.name); ...@@ -346,9 +352,11 @@ new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
if (IS_ERR(temp)) if (IS_ERR(temp))
goto out; goto out;
ret = -ENOENT; ret = -ENOENT;
if (temp->d_inode) if (temp->d_inode) {
ret = -ENOTDIR;
if (S_ISDIR(temp->d_inode->i_mode))
ret = msdos_rmdir (dir, temp); ret = msdos_rmdir (dir, temp);
d_drop(temp); }
dput (temp); dput (temp);
goto out; goto out;
...@@ -385,7 +393,6 @@ new_dentry->d_parent->d_name.name, new_dentry->d_name.name); ...@@ -385,7 +393,6 @@ new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
sizeof (data.stat))) sizeof (data.stat)))
ret = 0; ret = 0;
} }
d_drop(dret);
dput(dret); dput(dret);
goto out; goto out;
} }
......
...@@ -177,17 +177,15 @@ void umsdos_endlookup (struct inode *dir) ...@@ -177,17 +177,15 @@ void umsdos_endlookup (struct inode *dir)
static int is_sticky(struct inode *dir, int uid) static int is_sticky(struct inode *dir, int uid)
{ {
return !((dir->i_mode & S_ISVTX) == 0 || return !((dir->i_mode & S_ISVTX) == 0 ||
capable (CAP_FOWNER) ||
current->fsuid == uid || 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, static int umsdos_nevercreat (struct inode *dir, struct dentry *dentry,
int errcod) int errcod)
{ {
const char *name = dentry->d_name.name;
int len = dentry->d_name.len;
int ret = 0; int ret = 0;
if (umsdos_is_pseudodos (dir, dentry)) { if (umsdos_is_pseudodos (dir, dentry)) {
...@@ -198,20 +196,6 @@ static int umsdos_nevercreat (struct inode *dir, struct dentry *dentry, ...@@ -198,20 +196,6 @@ static int umsdos_nevercreat (struct inode *dir, struct dentry *dentry,
* The pseudo sub-directory /DOS can't be removed! * The pseudo sub-directory /DOS can't be removed!
* EPERM is returned. * 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; ret = errcod;
} }
return ret; return ret;
...@@ -269,10 +253,9 @@ static int umsdos_create_any (struct inode *dir, struct dentry *dentry, ...@@ -269,10 +253,9 @@ static int umsdos_create_any (struct inode *dir, struct dentry *dentry,
info.entry.gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid; 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.ctime = info.entry.atime = info.entry.mtime = CURRENT_TIME;
info.entry.nlink = 1; info.entry.nlink = 1;
umsdos_lockcreate (dir);
ret = umsdos_newentry (dentry->d_parent, &info); ret = umsdos_newentry (dentry->d_parent, &info);
if (ret) if (ret)
goto out_unlock; goto out;
/* do a real lookup to get the short name dentry */ /* do a real lookup to get the short name dentry */
fake = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname, fake = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname,
...@@ -281,43 +264,49 @@ static int umsdos_create_any (struct inode *dir, struct dentry *dentry, ...@@ -281,43 +264,49 @@ static int umsdos_create_any (struct inode *dir, struct dentry *dentry,
if (IS_ERR(fake)) if (IS_ERR(fake))
goto out_remove; goto out_remove;
/* keep the short name anonymous ... */
if (dentry != fake)
d_drop(fake);
/* should not exist yet ... */ /* should not exist yet ... */
ret = -EEXIST; ret = -EEXIST;
if (fake->d_inode) if (fake->d_inode)
goto out_remove; goto out_remove_dput;
ret = msdos_create (dir, fake, S_IFREG | 0777); ret = msdos_create (dir, fake, S_IFREG | 0777);
if (ret) if (ret)
goto out_remove; goto out_remove_dput;
inode = fake->d_inode;
/* /*
* Note! The long and short name might be the same, * Note! The long and short name might be the same,
* so check first before doing the instantiate ... * so check first before doing the instantiate ...
*/ */
if (dentry != fake) { if (dentry != fake) {
inode = fake->d_inode;
inode->i_count++; inode->i_count++;
d_instantiate (dentry, inode); d_instantiate (dentry, inode);
} }
umsdos_lookup_patch_new(dentry, &info.entry, info.f_pos); dput(fake);
goto out_dput; 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: out_remove:
if (ret == -EEXIST) if (ret == -EEXIST)
printk(KERN_WARNING "UMSDOS: out of sync, deleting %s/%s\n", printk(KERN_WARNING "UMSDOS: out of sync, deleting %s/%s\n",
dentry->d_parent->d_name.name, info.fake.fname); dentry->d_parent->d_name.name, info.fake.fname);
umsdos_delentry (dentry->d_parent, &info, S_ISDIR (info.entry.mode)); umsdos_delentry (dentry->d_parent, &info, S_ISDIR (info.entry.mode));
goto out;
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;
} }
/* /*
...@@ -340,7 +329,6 @@ int UMSDOS_create (struct inode *dir, struct dentry *dentry, int mode) ...@@ -340,7 +329,6 @@ int UMSDOS_create (struct inode *dir, struct dentry *dentry, int mode)
static void umsdos_ren_init (struct umsdos_info *new_info, static void umsdos_ren_init (struct umsdos_info *new_info,
struct umsdos_info *old_info) struct umsdos_info *old_info)
{ {
/* != 0, this is the value of flags */
new_info->entry.mode = old_info->entry.mode; new_info->entry.mode = old_info->entry.mode;
new_info->entry.rdev = old_info->entry.rdev; new_info->entry.rdev = old_info->entry.rdev;
new_info->entry.uid = old_info->entry.uid; new_info->entry.uid = old_info->entry.uid;
...@@ -373,7 +361,8 @@ static int umsdos_rename_f (struct inode *old_dir, struct dentry *old_dentry, ...@@ -373,7 +361,8 @@ static int umsdos_rename_f (struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry, struct inode *new_dir, struct dentry *new_dentry,
int flags) 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; int err, ret, rehash = 0;
struct umsdos_info old_info; struct umsdos_info old_info;
struct umsdos_info new_info; struct umsdos_info new_info;
...@@ -407,8 +396,12 @@ static int umsdos_rename_f (struct inode *old_dir, struct dentry *old_dentry, ...@@ -407,8 +396,12 @@ static int umsdos_rename_f (struct inode *old_dir, struct dentry *old_dentry,
/* check sticky bit on old_dir */ /* check sticky bit on old_dir */
ret = -EPERM; 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; goto out_unlock;
}
/* /*
* Check whether the new_name already exists, and * Check whether the new_name already exists, and
...@@ -470,6 +463,34 @@ old_dentry->d_parent->d_name.name, old_info.entry.name, rehash); ...@@ -470,6 +463,34 @@ old_dentry->d_parent->d_name.name, old_info.entry.name, rehash);
/* short and long name dentries match? */ /* short and long name dentries match? */
if (old == old_dentry) if (old == old_dentry)
dput(old); 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 = umsdos_lookup_dentry(new_dentry->d_parent, new_info.fake.fname,
new_info.fake.len, 1); new_info.fake.len, 1);
...@@ -481,27 +502,21 @@ old_dentry->d_parent->d_name.name, old_info.entry.name, rehash); ...@@ -481,27 +502,21 @@ old_dentry->d_parent->d_name.name, old_info.entry.name, rehash);
ret); ret);
goto out_dput; goto out_dput;
} }
/* #ifdef UMSDOS_PARANOIA
* Note! If the new short- and long-name dentries are if (new->d_inode != new_dentry->d_inode)
* aliases, the target name will be destroyed by the printk("umsdos_rename_f: new %s/%s, inode %p!=%p??\n",
* msdos-level rename. If in addition the old dentries new->d_parent->d_name.name, new->d_name.name, new->d_inode,new_dentry->d_inode);
* _aren't_ aliased, we'll need the original new name #endif
* for the final d_move, and so must make a copy here. /* short and long name dentries match? */
* if (new == new_dentry)
* Welcome to the mysteries of the dcache ...
*/
if (new == new_dentry) {
dput(new); 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 */ /* Do the msdos-level rename */
ret = msdos_rename (old_dir, old, new_dir, new); ret = msdos_rename (old_dir, old, new_dir, new);
Printk(("umsdos_rename_f: now %s/%s, ret=%d\n", Printk(("umsdos_rename_f: now %s/%s, ret=%d\n",
...@@ -534,23 +549,31 @@ ret, new_dentry->d_parent->d_name.name, new_info.entry.name)); ...@@ -534,23 +549,31 @@ ret, new_dentry->d_parent->d_name.name, new_info.entry.name));
err); 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 * Check whether to update the dcache ... if both
* old and new dentries match, it's already correct. * old and new dentries match, it's already correct.
* If the targets were aliases, the old short-name
* dentry has the original target name.
*/ */
if (new_dentry != new) { 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); d_move(old_dentry, new_dentry);
} else if (old_dentry != old) { }
/* new dentry was destroyed ... */ /* Check whether the old inode changed ... */
d_drop(new_dentry); if (old_dentry->d_inode != old_inode) {
d_add(new_target, NULL); umsdos_lookup_patch_new(old_dentry, &new_info);
d_move(old_dentry, new_target);
} }
/* /*
...@@ -559,8 +582,12 @@ ret, new_dentry->d_parent->d_name.name, new_info.entry.name)); ...@@ -559,8 +582,12 @@ ret, new_dentry->d_parent->d_name.name, new_info.entry.name));
*/ */
umsdos_set_dirinfo_new(old_dentry, new_info.f_pos); 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: out_unlock:
dput(new_target);
dput(old_emd); dput(old_emd);
umsdos_unlockcreate (old_dir); umsdos_unlockcreate (old_dir);
umsdos_unlockcreate (new_dir); umsdos_unlockcreate (new_dir);
...@@ -585,6 +612,8 @@ ret, new_dentry->d_parent->d_name.name, new_info.entry.name)); ...@@ -585,6 +612,8 @@ ret, new_dentry->d_parent->d_name.name, new_info.entry.name));
* Let's go for simplicity... * Let's go for simplicity...
*/ */
extern struct inode_operations umsdos_symlink_inode_operations;
static int umsdos_symlink_x (struct inode *dir, struct dentry *dentry, static int umsdos_symlink_x (struct inode *dir, struct dentry *dentry,
const char *symname, int mode, char flags) const char *symname, int mode, char flags)
{ {
...@@ -596,29 +625,28 @@ dentry->d_parent->d_name.name, dentry->d_name.name, symname)); ...@@ -596,29 +625,28 @@ dentry->d_parent->d_name.name, dentry->d_name.name, symname));
ret = umsdos_create_any (dir, dentry, mode, 0, flags); ret = umsdos_create_any (dir, dentry, mode, 0, flags);
if (ret) { if (ret) {
printk("umsdos_symlink: create failed, ret=%d\n", ret); printk(KERN_WARNING
"umsdos_symlink: create failed, ret=%d\n", ret);
goto out; goto out;
} }
fill_new_filp (&filp, dentry); fill_new_filp (&filp, dentry);
len = strlen (symname); len = strlen (symname);
ret = umsdos_file_write_kmem_real (&filp, symname, len); ret = umsdos_file_write_kmem_real (&filp, symname, len);
if (ret >= 0) { if (ret < 0)
if (ret != len) { goto out_unlink;
ret = -EIO; if (ret != len)
printk (KERN_WARNING goto out_error;
"UMSDOS: Can't write symbolic link data\n");
} else {
ret = 0; ret = 0;
}
}
if (ret != 0) {
printk("umsdos_symlink: write failed, unlinking\n");
UMSDOS_unlink (dir, dentry);
}
out: out:
return ret; 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 @@ olddentry->d_parent->d_name.name, olddentry->d_name.name); ...@@ -665,7 +693,15 @@ olddentry->d_parent->d_name.name, olddentry->d_name.name);
if (!buffer) if (!buffer)
goto out; 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. * Parse the name and get the visible directory entry.
...@@ -802,10 +838,7 @@ olddentry->d_parent->d_name.name, olddentry->d_name.name, path)); ...@@ -802,10 +838,7 @@ olddentry->d_parent->d_name.name, olddentry->d_name.name, path));
ret = umsdos_symlink_x (dir, dentry, path, S_IFREG | 0777,UMSDOS_HLINK); ret = umsdos_symlink_x (dir, dentry, path, S_IFREG | 0777,UMSDOS_HLINK);
out_unlock: out_unlock:
umsdos_unlockcreate (olddir); /* remain locked for the call to notify_change ... */
umsdos_unlockcreate (dir);
free_page(buffer);
out:
if (ret == 0) { if (ret == 0) {
struct iattr newattrs; struct iattr newattrs;
...@@ -819,8 +852,14 @@ Printk(("UMSDOS_link: linked %s/%s, ino=%ld, nlink=%d\n", ...@@ -819,8 +852,14 @@ Printk(("UMSDOS_link: linked %s/%s, ino=%ld, nlink=%d\n",
olddentry->d_parent->d_name.name, olddentry->d_name.name, olddentry->d_parent->d_name.name, olddentry->d_name.name,
oldinode->i_ino, oldinode->i_nlink)); oldinode->i_ino, oldinode->i_nlink));
newattrs.ia_valid = 0; 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)); Printk (("umsdos_link %d\n", ret));
return ret; return ret;
} }
...@@ -854,7 +893,6 @@ int UMSDOS_mkdir (struct inode *dir, struct dentry *dentry, int mode) ...@@ -854,7 +893,6 @@ int UMSDOS_mkdir (struct inode *dir, struct dentry *dentry, int mode)
if (ret) if (ret)
goto out; goto out;
umsdos_lockcreate (dir);
info.entry.mode = mode | S_IFDIR; info.entry.mode = mode | S_IFDIR;
info.entry.rdev = 0; info.entry.rdev = 0;
info.entry.uid = current->fsuid; info.entry.uid = current->fsuid;
...@@ -864,26 +902,36 @@ int UMSDOS_mkdir (struct inode *dir, struct dentry *dentry, int mode) ...@@ -864,26 +902,36 @@ int UMSDOS_mkdir (struct inode *dir, struct dentry *dentry, int mode)
info.entry.nlink = 1; info.entry.nlink = 1;
ret = umsdos_newentry (dentry->d_parent, &info); ret = umsdos_newentry (dentry->d_parent, &info);
if (ret) if (ret)
goto out_unlock; goto out;
/* lookup the short name dentry */ /* lookup the short name dentry */
temp = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname, temp = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname,
info.fake.len, 1); info.fake.len, 1);
ret = PTR_ERR(temp); ret = PTR_ERR(temp);
if (IS_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 */ /* Make sure the short name doesn't exist */
ret = -EEXIST; ret = -EEXIST;
if (temp->d_inode) { if (temp->d_inode) {
printk("umsdos_mkdir: short name %s/%s exists\n", printk("umsdos_mkdir: short name %s/%s exists\n",
dentry->d_parent->d_name.name, info.fake.fname); dentry->d_parent->d_name.name, info.fake.fname);
goto out_remove; goto out_remove_dput;
} }
ret = msdos_mkdir (dir, temp, mode); ret = msdos_mkdir (dir, temp, mode);
if (ret) 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, * Note! The long and short name might be the same,
...@@ -892,11 +940,11 @@ dentry->d_parent->d_name.name, info.fake.fname); ...@@ -892,11 +940,11 @@ dentry->d_parent->d_name.name, info.fake.fname);
if (dentry != temp) { if (dentry != temp) {
if (dentry->d_inode) if (dentry->d_inode)
printk("umsdos_mkdir: dentry not negative!\n"); printk("umsdos_mkdir: dentry not negative!\n");
inode = temp->d_inode;
inode->i_count++; inode->i_count++;
d_instantiate(dentry, inode); 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 * Create the EMD file, and set up the dir so it is
...@@ -907,22 +955,20 @@ printk("umsdos_mkdir: dentry not negative!\n"); ...@@ -907,22 +955,20 @@ printk("umsdos_mkdir: dentry not negative!\n");
err = umsdos_make_emd(dentry); err = umsdos_make_emd(dentry);
umsdos_setup_dir(dentry); umsdos_setup_dir(dentry);
out_dput: up(&inode->i_sem);
/* kill off the short name dentry */
if (temp != dentry)
d_drop(temp);
dput(temp); dput(temp);
out_unlock:
umsdos_unlockcreate (dir);
out: 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; return ret;
/* an error occurred ... remove EMD entry. */ /* an error occurred ... remove EMD entry. */
out_remove_dput:
dput(temp);
out_remove: out_remove:
umsdos_delentry (dentry->d_parent, &info, 1); umsdos_delentry (dentry->d_parent, &info, 1);
goto out_dput; goto out;
} }
/* /*
...@@ -961,43 +1007,37 @@ int UMSDOS_rmdir (struct inode *dir, struct dentry *dentry) ...@@ -961,43 +1007,37 @@ int UMSDOS_rmdir (struct inode *dir, struct dentry *dentry)
if (ret) if (ret)
goto out; goto out;
umsdos_lockcreate (dir);
ret = -EBUSY; ret = -EBUSY;
if (dentry->d_count > 1) {
shrink_dcache_parent(dentry); shrink_dcache_parent(dentry);
if (dentry->d_count > 1) { if (dentry->d_count > 1)
printk("umsdos_rmdir: %s/%s busy\n", goto out;
dentry->d_parent->d_name.name, dentry->d_name.name);
goto out_unlock;
}
}
/* check the sticky bit */ /* check the sticky bit */
ret = -EPERM; ret = -EPERM;
if (is_sticky(dir, dentry->d_inode->i_uid)) { if (is_sticky(dir, dentry->d_inode->i_uid)) {
printk("umsdos_rmdir: %s/%s is sticky\n", printk("umsdos_rmdir: %s/%s is sticky\n",
dentry->d_parent->d_name.name, dentry->d_name.name); 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 */ /* check whether the EMD is empty */
empty = umsdos_isempty (dentry);
ret = -ENOTEMPTY; ret = -ENOTEMPTY;
if (empty == 0) empty = umsdos_isempty (dentry);
goto out_unlock;
/* Have to remove the EMD file? */ /* Have to remove the EMD file? */
if (empty == 1) { if (empty == 1) {
struct dentry *demd; struct dentry *demd;
Printk (("UMSDOS_rmdir: unlinking empty EMD err=%d", err)); Printk (("UMSDOS_rmdir: unlinking empty EMD err=%d", err));
ret = -ENOTEMPTY;
/* see if there's an EMD file ... */
demd = umsdos_get_emd_dentry(dentry); demd = umsdos_get_emd_dentry(dentry);
if (IS_ERR(demd)) if (!IS_ERR(demd)) {
goto out_unlock; err = -ENOENT;
if (demd->d_inode)
err = msdos_unlink (dentry->d_inode, demd); err = msdos_unlink (dentry->d_inode, demd);
#ifdef UMSDOS_PARANOIA #ifdef UMSDOS_PARANOIA
if (err) if (err)
...@@ -1005,9 +1045,14 @@ printk("umsdos_rmdir: EMD %s/%s unlink failed, err=%d\n", ...@@ -1005,9 +1045,14 @@ printk("umsdos_rmdir: EMD %s/%s unlink failed, err=%d\n",
demd->d_parent->d_name.name, demd->d_name.name, err); demd->d_parent->d_name.name, demd->d_name.name, err);
#endif #endif
dput(demd); dput(demd);
if (err) if (!err)
goto out_unlock; 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); umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
/* Call findentry to complete the mangling */ /* Call findentry to complete the mangling */
...@@ -1016,14 +1061,23 @@ demd->d_parent->d_name.name, demd->d_name.name, err); ...@@ -1016,14 +1061,23 @@ demd->d_parent->d_name.name, demd->d_name.name, err);
info.fake.len, 1); info.fake.len, 1);
ret = PTR_ERR(temp); ret = PTR_ERR(temp);
if (IS_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); dput(temp);
Printk(("umsdos_rmdir: %s/%s, short matches long\n", else
dentry->d_parent->d_name.name, dentry->d_name.name)); 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 @@ printk("umsdos_rmdir: delentry %s failed, ret=%d\n", info.entry.name, ret); ...@@ -1043,15 +1097,11 @@ printk("umsdos_rmdir: delentry %s failed, ret=%d\n", info.entry.name, ret);
/* dput() temp if we didn't do it above */ /* dput() temp if we didn't do it above */
out_dput: out_dput:
if (temp != dentry) { if (temp != dentry) {
d_drop(temp);
dput(temp); dput(temp);
if (!ret) if (!ret)
d_delete (dentry); d_delete (dentry);
} }
out_unlock:
umsdos_unlockcreate (dir);
out: out:
Printk (("umsdos_rmdir %d\n", ret)); Printk (("umsdos_rmdir %d\n", ret));
return ret; return ret;
...@@ -1196,6 +1246,10 @@ link->d_parent->d_name.name, link->d_name.name, ret)); ...@@ -1196,6 +1246,10 @@ link->d_parent->d_name.name, link->d_name.name, ret));
/* /*
* If this was the last linked reference, delete it now. * 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) { if (inode->i_nlink <= 1) {
ret = UMSDOS_unlink (link->d_parent->d_inode, link); ret = UMSDOS_unlink (link->d_parent->d_inode, link);
...@@ -1208,7 +1262,7 @@ link->d_parent->d_name.name, link->d_name.name, ret)); ...@@ -1208,7 +1262,7 @@ link->d_parent->d_name.name, link->d_name.name, ret));
struct iattr newattrs; struct iattr newattrs;
inode->i_nlink--; inode->i_nlink--;
newattrs.ia_valid = 0; newattrs.ia_valid = 0;
ret = UMSDOS_notify_change (link, &newattrs); ret = umsdos_notify_change_locked(link, &newattrs);
} }
out_cleanup: out_cleanup:
...@@ -1227,38 +1281,49 @@ link->d_parent->d_name.name, link->d_name.name, ret)); ...@@ -1227,38 +1281,49 @@ link->d_parent->d_name.name, link->d_name.name, ret));
int UMSDOS_rename (struct inode *old_dir, struct dentry *old_dentry, int UMSDOS_rename (struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry) struct inode *new_dir, struct dentry *new_dentry)
{ {
struct dentry *new_target;
int ret; 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); ret = umsdos_nevercreat (new_dir, new_dentry, -EEXIST);
if (ret) if (ret)
goto out; 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 * If the target already exists, delete it first.
* the file really exists ... track this down!
*/ */
ret = -EIO; if (new_dentry->d_inode) {
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;
}
/* This is not terribly efficient but should work. */
if (S_ISDIR(new_dentry->d_inode->i_mode)) if (S_ISDIR(new_dentry->d_inode->i_mode))
ret = UMSDOS_rmdir (new_dir, new_dentry); ret = UMSDOS_rmdir (new_dir, new_dentry);
else else
ret = UMSDOS_unlink (new_dir, new_dentry); ret = UMSDOS_unlink (new_dir, new_dentry);
if (ret) if (ret)
goto out; 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: out:
return ret; return ret;
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
extern struct dentry *saved_root;
extern struct inode *pseudo_root; extern struct inode *pseudo_root;
extern struct dentry_operations umsdos_dentry_operations; extern struct dentry_operations umsdos_dentry_operations;
...@@ -64,9 +65,7 @@ static int UMSDOS_rreaddir (struct file *filp, void *dirbuf, filldir_t filldir) ...@@ -64,9 +65,7 @@ static int UMSDOS_rreaddir (struct file *filp, void *dirbuf, filldir_t filldir)
bufk.filldir = filldir; bufk.filldir = filldir;
bufk.dirbuf = dirbuf; bufk.dirbuf = dirbuf;
bufk.real_root = pseudo_root && bufk.real_root = pseudo_root && (dir == saved_root->d_inode);
dir->i_ino == UMSDOS_ROOT_INO &&
dir->i_sb == pseudo_root->i_sb;
return fat_readdir (filp, &bufk, rdir_filldir); return fat_readdir (filp, &bufk, rdir_filldir);
} }
...@@ -82,30 +81,41 @@ static int UMSDOS_rreaddir (struct file *filp, void *dirbuf, filldir_t filldir) ...@@ -82,30 +81,41 @@ static int UMSDOS_rreaddir (struct file *filp, void *dirbuf, filldir_t filldir)
*/ */
int umsdos_rlookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo) 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; 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] == '.' && 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"); printk (KERN_WARNING "umsdos_rlookup_x: we are at pseudo-root thingy?\n");
pseudo_root->i_count++; pseudo_root->i_count++;
d_add(dentry, pseudo_root); d_add(dentry, pseudo_root);
ret = 0; ret = 0;
goto out; goto out;
} }
#endif
ret = msdos_lookup (dir, dentry); ret = msdos_lookup (dir, dentry);
if (ret) { if (ret) {
printk(KERN_WARNING "umsdos_rlookup_x: lookup failed, ret=%d\n", printk(KERN_WARNING
ret); "umsdos_rlookup_x: %s/%s failed, ret=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name,ret);
goto out; goto out;
} }
inode = dentry->d_inode; if (dentry->d_inode) {
if (inode) { /* We must install the proper function table
if (inode == pseudo_root && !nopseudo) { * 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 /* #Specification: pseudo root / DOS/linux
* Even in the real root directory (c:\), the directory * Even in the real root directory (c:\), the directory
* /linux won't show * /linux won't show
...@@ -114,20 +124,11 @@ printk(KERN_WARNING "umsdos_rlookup_x: do the pseudo-thingy...\n"); ...@@ -114,20 +124,11 @@ printk(KERN_WARNING "umsdos_rlookup_x: do the pseudo-thingy...\n");
/* make the dentry negative */ /* make the dentry negative */
d_delete(dentry); d_delete(dentry);
} }
else if (S_ISDIR (inode->i_mode)) { #endif
/* 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);
}
} }
out: out:
/* always install our dentry ops ... */ /* always install our dentry ops ... */
dentry->d_op = &umsdos_dentry_operations; dentry->d_op = &umsdos_dentry_operations;
PRINTK ((KERN_DEBUG "umsdos_rlookup_x: returning %d\n", ret));
return ret; return ret;
} }
...@@ -168,18 +169,18 @@ static int UMSDOS_rrmdir ( struct inode *dir, struct dentry *dentry) ...@@ -168,18 +169,18 @@ static int UMSDOS_rrmdir ( struct inode *dir, struct dentry *dentry)
if (umsdos_is_pseudodos (dir, dentry)) if (umsdos_is_pseudodos (dir, dentry))
goto out; goto out;
umsdos_lockcreate (dir);
ret = -EBUSY; ret = -EBUSY;
if (dentry->d_count > 1) { if (dentry->d_count > 1) {
shrink_dcache_parent(dentry); shrink_dcache_parent(dentry);
if (dentry->d_count > 1) if (dentry->d_count > 1)
goto out_unlock; goto out;
} }
ret = msdos_rmdir (dir, dentry); ret = msdos_rmdir (dir, dentry);
if (ret != -ENOTEMPTY) if (ret != -ENOTEMPTY)
goto out_unlock; goto out;
down(&dentry->d_inode->i_sem);
empty = umsdos_isempty (dentry); empty = umsdos_isempty (dentry);
if (empty == 1) { if (empty == 1) {
struct dentry *demd; struct dentry *demd;
...@@ -192,14 +193,14 @@ static int UMSDOS_rrmdir ( struct inode *dir, struct dentry *dentry) ...@@ -192,14 +193,14 @@ static int UMSDOS_rrmdir ( struct inode *dir, struct dentry *dentry)
ret = msdos_unlink (dentry->d_inode, demd); ret = msdos_unlink (dentry->d_inode, demd);
dput(demd); dput(demd);
} }
if (ret)
goto out_unlock;
} }
up(&dentry->d_inode->i_sem);
if (ret)
goto out;
/* now retry the original ... */ /* now retry the original ... */
ret = msdos_rmdir (dir, dentry); ret = msdos_rmdir (dir, dentry);
out_unlock:
umsdos_unlockcreate (dir);
out: out:
return ret; return ret;
} }
......
...@@ -520,6 +520,7 @@ struct ext2_dir_entry_2 { ...@@ -520,6 +520,7 @@ struct ext2_dir_entry_2 {
extern int ext2_permission (struct inode *, int); extern int ext2_permission (struct inode *, int);
/* balloc.c */ /* balloc.c */
extern int ext2_group_sparse(int group);
extern int ext2_new_block (const struct inode *, unsigned long, extern int ext2_new_block (const struct inode *, unsigned long,
__u32 *, __u32 *, int *); __u32 *, __u32 *, int *);
extern void ext2_free_blocks (const struct inode *, unsigned long, extern void ext2_free_blocks (const struct inode *, unsigned long,
......
...@@ -165,19 +165,23 @@ struct dqstats { ...@@ -165,19 +165,23 @@ struct dqstats {
#define DQ_FAKE 0x40 /* no limits only usage */ #define DQ_FAKE 0x40 /* no limits only usage */
struct dquot { 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) */ unsigned int dq_id; /* ID this applies to (uid, gid) */
short dq_type; /* Type of quota */
kdev_t dq_dev; /* Device this applies to */ kdev_t dq_dev; /* Device this applies to */
short dq_type; /* Type of quota */
short dq_flags; /* See DQ_* */ short dq_flags; /* See DQ_* */
short dq_count; /* Reference count */ unsigned long dq_referenced; /* Number of times this dquot was
unsigned long dq_referenced; /* Number of times this dquot was referenced during its lifetime */ referenced during its lifetime */
struct vfsmount *dq_mnt; /* VFS_mount_point this applies to */
struct dqblk dq_dqb; /* Diskquota usage */ 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 #define NODQUOT (struct dquot *)NULL
......
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
#include <linux/config.h> #include <linux/config.h>
#include <linux/sunrpc/sched.h> #include <linux/sunrpc/sched.h>
/* size of the nodename buffer */
#define UNX_MAXNODENAME 32
/* /*
* Client user credentials * Client user credentials
......
...@@ -52,6 +52,9 @@ struct rpc_clnt { ...@@ -52,6 +52,9 @@ struct rpc_clnt {
struct rpc_portmap cl_pmap; /* port mapping */ struct rpc_portmap cl_pmap; /* port mapping */
struct rpc_wait_queue cl_bindwait; /* waiting on getport() */ 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_timeout cl_xprt->timeout
#define cl_prog cl_pmap.pm_prog #define cl_prog cl_pmap.pm_prog
......
...@@ -71,7 +71,7 @@ enum { ...@@ -71,7 +71,7 @@ enum {
}; };
#define TCP_STATE_MASK 0xF #define TCP_STATE_MASK 0xF
#define TCP_ACTION_FIN 1 << 7 #define TCP_ACTION_FIN (1 << 7)
enum { enum {
TCPF_ESTABLISHED = (1 << 1), TCPF_ESTABLISHED = (1 << 1),
......
...@@ -2,31 +2,14 @@ ...@@ -2,31 +2,14 @@
void check_page_tables (void); void check_page_tables (void);
/* dir.c 22/06/95 00.22.12 */ /* 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, int dummy_dir_read ( struct file *filp,
char *buf, char *buf,
size_t size, size_t size,
loff_t *count); loff_t *count);
char * umsdos_d_path(struct dentry *, char *, int); char * umsdos_d_path(struct dentry *, char *, int);
void umsdos_lookup_patch_new(struct dentry *, struct umsdos_dirent *, off_t); void umsdos_lookup_patch_new(struct dentry *, struct umsdos_info *);
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);
int umsdos_is_pseudodos (struct inode *dir, struct dentry *dentry); int umsdos_is_pseudodos (struct inode *dir, struct dentry *dentry);
int umsdos_lookup_x ( int umsdos_lookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo);
struct inode *dir,
struct dentry *dentry,
int nopseudo);
int UMSDOS_lookup(struct inode *, struct dentry *); int UMSDOS_lookup(struct inode *, struct dentry *);
struct dentry *umsdos_lookup_dentry(struct dentry *, char *, int, int); struct dentry *umsdos_lookup_dentry(struct dentry *, char *, int, int);
...@@ -52,7 +35,6 @@ ssize_t umsdos_emd_dir_read (struct file *filp, ...@@ -52,7 +35,6 @@ ssize_t umsdos_emd_dir_read (struct file *filp,
struct dentry *umsdos_get_emd_dentry(struct dentry *); struct dentry *umsdos_get_emd_dentry(struct dentry *);
int umsdos_have_emd(struct dentry *); int umsdos_have_emd(struct dentry *);
int umsdos_make_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_emd_dir_readentry (struct file *, struct umsdos_dirent *);
int umsdos_newentry (struct dentry *, struct umsdos_info *); int umsdos_newentry (struct dentry *, struct umsdos_info *);
int umsdos_newhidden (struct dentry *, struct umsdos_info *); int umsdos_newhidden (struct dentry *, struct umsdos_info *);
...@@ -63,32 +45,20 @@ int umsdos_isempty (struct dentry *); ...@@ -63,32 +45,20 @@ int umsdos_isempty (struct dentry *);
/* file.c 25/01/95 02.25.38 */ /* file.c 25/01/95 02.25.38 */
/* inode.c 12/06/95 09.49.40 */ /* 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); 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_read_inode (struct inode *);
void UMSDOS_write_inode (struct inode *); void UMSDOS_write_inode (struct inode *);
int UMSDOS_notify_change (struct dentry *, struct iattr *attr); 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 *); void UMSDOS_put_inode (struct inode *);
int UMSDOS_statfs (struct super_block *, struct statfs *, int); int UMSDOS_statfs (struct super_block *, struct statfs *, int);
struct super_block *UMSDOS_read_super (struct super_block *, void *, int); struct super_block *UMSDOS_read_super (struct super_block *, void *, int);
void UMSDOS_put_super (struct super_block *); 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(struct dentry *);
void umsdos_setup_dir_inode (struct inode *inode);
void umsdos_set_dirinfo_new(struct dentry *, off_t); 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); int umsdos_isinit (struct inode *inode);
void umsdos_patch_dentry_inode (struct dentry *, off_t); 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); int umsdos_get_dirowner (struct inode *inode, struct inode **result);
/* ioctl.c 22/06/95 00.22.08 */ /* ioctl.c 22/06/95 00.22.08 */
...@@ -96,6 +66,7 @@ int UMSDOS_ioctl_dir (struct inode *dir, ...@@ -96,6 +66,7 @@ int UMSDOS_ioctl_dir (struct inode *dir,
struct file *filp, struct file *filp,
unsigned int cmd, unsigned int cmd,
unsigned long data); unsigned long data);
/* mangle.c 25/01/95 02.25.38 */ /* mangle.c 25/01/95 02.25.38 */
void umsdos_manglename (struct umsdos_info *info); void umsdos_manglename (struct umsdos_info *info);
int umsdos_evalrecsize (int len); int umsdos_evalrecsize (int len);
...@@ -135,9 +106,13 @@ int UMSDOS_rename (struct inode *old_dir, ...@@ -135,9 +106,13 @@ int UMSDOS_rename (struct inode *old_dir,
struct dentry *new_dentry); struct dentry *new_dentry);
/* rdir.c 22/03/95 03.31.42 */ /* rdir.c 22/03/95 03.31.42 */
int umsdos_rlookup_x (struct inode *dir, int umsdos_rlookup_x (struct inode *dir, struct dentry *dentry, int nopseudo);
struct dentry *dentry, int UMSDOS_rlookup (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 */ /* 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);
...@@ -62,12 +62,14 @@ struct umsdos_inode_info { ...@@ -62,12 +62,14 @@ struct umsdos_inode_info {
struct msdos_inode_info msdos_info; struct msdos_inode_info msdos_info;
struct pipe_inode_info pipe_info; struct pipe_inode_info pipe_info;
struct dir_locking_info dir_info; struct dir_locking_info dir_info;
} u; /* Simply a filler, never referenced by fs/umsdos/... */ } u;
unsigned long i_dir_owner; /* Inode of the dir which hold this entry */ int i_patched; /* Inode has been patched */
unsigned long i_emd_owner; /* Inode of the EMD file of i_dir_owner */ 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 */ off_t pos; /* Entry offset in the emd_owner file */
/* The rest is used only if this inode describe a directory */ /* The rest is used only if this inode describes a directory */
unsigned long i_emd_dir; /* Inode of the EMD file of this inode */ struct dentry *i_emd_dentry; /* EMD dentry for this directory */
unsigned long i_emd_dir; /* Inode of the EMD file */
}; };
#endif #endif
...@@ -598,9 +598,9 @@ unsigned int tcp_poll(struct file * file, struct socket *sock, poll_table *wait) ...@@ -598,9 +598,9 @@ unsigned int tcp_poll(struct file * file, struct socket *sock, poll_table *wait)
sk->urginline || !tp->urg_data)) sk->urginline || !tp->urg_data))
mask |= POLLIN | POLLRDNORM; mask |= POLLIN | POLLRDNORM;
/* Always wake the user up when an error occurred */ if (sock_wspace(sk) >= tcp_min_write_space(sk, tp))
if (sock_wspace(sk) >= tcp_min_write_space(sk, tp) || sk->err)
mask |= POLLOUT | POLLWRNORM; mask |= POLLOUT | POLLWRNORM;
if (tp->urg_data & URG_VALID) if (tp->urg_data & URG_VALID)
mask |= POLLPRI; mask |= POLLPRI;
} }
...@@ -1458,7 +1458,8 @@ void tcp_close(struct sock *sk, unsigned long timeout) ...@@ -1458,7 +1458,8 @@ void tcp_close(struct sock *sk, unsigned long timeout)
* reader process may not have drained the data yet! * reader process may not have drained the data yet!
*/ */
while((skb=__skb_dequeue(&sk->receive_queue))!=NULL) { 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); kfree_skb(skb);
} }
......
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
#include <linux/malloc.h> #include <linux/malloc.h>
#include <linux/socket.h> #include <linux/socket.h>
#include <linux/in.h> #include <linux/in.h>
#include <linux/utsname.h>
#include <linux/sunrpc/clnt.h> #include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/auth.h> #include <linux/sunrpc/auth.h>
...@@ -28,13 +27,7 @@ struct unx_cred { ...@@ -28,13 +27,7 @@ struct unx_cred {
#define UNX_CRED_EXPIRE (60 * HZ) #define UNX_CRED_EXPIRE (60 * HZ)
#ifndef DONT_FILLIN_HOSTNAME #define UNX_WRITESLACK (21 + (UNX_MAXNODENAME >> 2))
/* # 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
#ifdef RPC_DEBUG #ifdef RPC_DEBUG
# define RPCDBG_FACILITY RPCDBG_AUTH # define RPCDBG_FACILITY RPCDBG_AUTH
...@@ -170,6 +163,7 @@ unx_match(struct rpc_task * task, struct rpc_cred *rcred) ...@@ -170,6 +163,7 @@ unx_match(struct rpc_task * task, struct rpc_cred *rcred)
static u32 * static u32 *
unx_marshal(struct rpc_task *task, u32 *p, int ruid) 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; struct unx_cred *cred = (struct unx_cred *) task->tk_cred;
u32 *base, *hold; u32 *base, *hold;
int i, n; int i, n;
...@@ -177,20 +171,15 @@ unx_marshal(struct rpc_task *task, u32 *p, int ruid) ...@@ -177,20 +171,15 @@ unx_marshal(struct rpc_task *task, u32 *p, int ruid)
*p++ = htonl(RPC_AUTH_UNIX); *p++ = htonl(RPC_AUTH_UNIX);
base = p++; base = p++;
*p++ = htonl(jiffies/HZ); *p++ = htonl(jiffies/HZ);
#ifndef DONT_FILLIN_HOSTNAME
/* /*
* Problem: The UTS name could change under us. We can't lock * Copy the UTS nodename captured when the client was created.
* here to handle this. On the other hand we can't really
* go building a bad RPC!
*/ */
if ((n = strlen((char *) system_utsname.nodename)) > UNX_MAXNODENAME) n = clnt->cl_nodelen;
n = UNX_MAXNODENAME;
*p++ = htonl(n); *p++ = htonl(n);
memcpy(p, system_utsname.nodename, n); memcpy(p, clnt->cl_nodename, n);
p += (n + 3) >> 2; p += (n + 3) >> 2;
#else
*p++ = 0;
#endif
if (ruid) { if (ruid) {
*p++ = htonl((u32) cred->uc_uid); *p++ = htonl((u32) cred->uc_uid);
*p++ = htonl((u32) cred->uc_gid); *p++ = htonl((u32) cred->uc_gid);
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/malloc.h> #include <linux/malloc.h>
#include <linux/in.h> #include <linux/in.h>
#include <linux/utsname.h>
#include <linux/sunrpc/clnt.h> #include <linux/sunrpc/clnt.h>
...@@ -101,6 +102,12 @@ rpc_create_client(struct rpc_xprt *xprt, char *servname, ...@@ -101,6 +102,12 @@ rpc_create_client(struct rpc_xprt *xprt, char *servname,
if (!rpcauth_create(flavor, clnt)) if (!rpcauth_create(flavor, clnt))
goto out_no_auth; 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: out:
return clnt; return clnt;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment