Commit d13a7654 authored by Linus Torvalds's avatar Linus Torvalds

Import 2.1.123pre3

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