Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
d13a7654
Commit
d13a7654
authored
Nov 23, 2007
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Import 2.1.123pre3
parent
36800b1c
Changes
35
Show whitespace changes
Inline
Side-by-side
Showing
35 changed files
with
1181 additions
and
1366 deletions
+1181
-1366
MAINTAINERS
MAINTAINERS
+1
-7
arch/i386/kernel/bios32.c
arch/i386/kernel/bios32.c
+23
-13
arch/i386/kernel/io_apic.c
arch/i386/kernel/io_apic.c
+16
-5
arch/i386/kernel/irq.c
arch/i386/kernel/irq.c
+3
-1
drivers/block/genhd.c
drivers/block/genhd.c
+1
-2
drivers/char/esp.c
drivers/char/esp.c
+7
-3
drivers/char/pc_keyb.c
drivers/char/pc_keyb.c
+6
-1
drivers/net/ppp.c
drivers/net/ppp.c
+1
-0
drivers/scsi/imm.c
drivers/scsi/imm.c
+1
-2
fs/dquot.c
fs/dquot.c
+306
-192
fs/ext2/balloc.c
fs/ext2/balloc.c
+7
-1
fs/ext2/super.c
fs/ext2/super.c
+30
-8
fs/isofs/inode.c
fs/isofs/inode.c
+175
-137
fs/isofs/rock.c
fs/isofs/rock.c
+38
-37
fs/namei.c
fs/namei.c
+56
-29
fs/nfs/dir.c
fs/nfs/dir.c
+4
-11
fs/nfs/inode.c
fs/nfs/inode.c
+10
-7
fs/proc/mem.c
fs/proc/mem.c
+4
-2
fs/super.c
fs/super.c
+11
-11
fs/umsdos/dir.c
fs/umsdos/dir.c
+23
-205
fs/umsdos/emd.c
fs/umsdos/emd.c
+18
-97
fs/umsdos/inode.c
fs/umsdos/inode.c
+106
-318
fs/umsdos/ioctl.c
fs/umsdos/ioctl.c
+16
-9
fs/umsdos/namei.c
fs/umsdos/namei.c
+229
-164
fs/umsdos/rdir.c
fs/umsdos/rdir.c
+31
-30
include/linux/ext2_fs.h
include/linux/ext2_fs.h
+1
-0
include/linux/quota.h
include/linux/quota.h
+13
-9
include/linux/sunrpc/auth.h
include/linux/sunrpc/auth.h
+2
-0
include/linux/sunrpc/clnt.h
include/linux/sunrpc/clnt.h
+3
-0
include/linux/tcp.h
include/linux/tcp.h
+1
-1
include/linux/umsdos_fs.p
include/linux/umsdos_fs.p
+13
-38
include/linux/umsdos_fs_i.h
include/linux/umsdos_fs_i.h
+7
-5
net/ipv4/tcp.c
net/ipv4/tcp.c
+4
-3
net/sunrpc/auth_unix.c
net/sunrpc/auth_unix.c
+7
-18
net/sunrpc/clnt.c
net/sunrpc/clnt.c
+7
-0
No files found.
MAINTAINERS
View file @
d13a7654
...
...
@@ -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
...
...
arch/i386/kernel/bios32.c
View file @
d13a7654
/*
* bios32.c - Low-Level PCI Access
*
* $Id: bios32.c,v 1.4
5 1998/08/15 10:41:04
mj Exp $
* $Id: bios32.c,v 1.4
8 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
...
...
arch/i386/kernel/io_apic.c
View file @
d13a7654
...
...
@@ -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
);
...
...
arch/i386/kernel/irq.c
View file @
d13a7654
...
...
@@ -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
);
...
...
drivers/block/genhd.c
View file @
d13a7654
...
...
@@ -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]"
);
...
...
drivers/char/esp.c
View file @
d13a7654
...
...
@@ -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
++
;
...
...
drivers/char/pc_keyb.c
View file @
d13a7654
...
...
@@ -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
);
...
...
drivers/net/ppp.c
View file @
d13a7654
...
...
@@ -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
);
...
...
drivers/scsi/imm.c
View file @
d13a7654
...
...
@@ -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
)
{
...
...
fs/dquot.c
View file @
d13a7654
...
...
@@ -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
;
...
...
fs/ext2/balloc.c
View file @
d13a7654
...
...
@@ -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 "
...
...
fs/ext2/super.c
View file @
d13a7654
...
...
@@ -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
;
...
...
fs/isofs/inode.c
View file @
d13a7654
...
...
@@ -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_firstdata
zone
=
((
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
:%l
d
\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 message
s and free resources.
*/
out_
no
_root:
printk
(
KERN_
ERR
"isofs_read_super: get root inode fail
ed
\n
"
);
out_
bad
_root:
printk
(
KERN_
WARNING
"isofs_read_super: root inode not initializ
ed
\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
;
b
lock
=
inode
->
i_ino
>>
ISOFS_BUFFER_BITS
(
inod
e
);
if
(
!
(
bh
=
bread
(
inode
->
i_dev
,
block
,
bufsize
))
)
{
printk
(
"unable to read i-node block
"
);
b
h
=
bread
(
inode
->
i_dev
,
block
,
bufsiz
e
);
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
;
...
...
fs/isofs/rock.c
View file @
d13a7654
...
...
@@ -54,17 +54,16 @@
{if (buffer) kfree(buffer); \
if (cont_extent){ \
int block, offset, offset1; \
struct buffer_head * bh; \
struct buffer_head *
p
bh; \
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
;
}
fs/namei.c
View file @
d13a7654
...
...
@@ -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
f
ollow
;
unsigned
int
f
lags
;
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? */
f
ollow
=
follow_link
;
f
lags
=
lookup_flags
;
if
(
c
)
{
char
tmp
;
f
ollow
|=
FOLLOW
_DIRECTORY
;
f
lags
|=
LOOKUP_FOLLOW
|
LOOKUP
_DIRECTORY
;
do
{
tmp
=
*++
name
;
}
while
(
tmp
==
'/'
);
if
(
tmp
)
f
ollow
|=
FOLLOW
_CONTINUE
;
f
lags
|=
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
,
f
ollow
);
base
=
do_follow_link
(
base
,
dentry
,
f
lags
);
if
(
IS_ERR
(
base
))
goto
return_base
;
dentry
=
ERR_PTR
(
-
ENOENT
);
inode
=
base
->
d_inode
;
if
(
f
ollow
&
FOLLOW
_DIRECTORY
)
{
if
(
f
lags
&
LOOKUP
_DIRECTORY
)
{
if
(
!
inode
)
break
;
goto
no_inode
;
dentry
=
ERR_PTR
(
-
ENOTDIR
);
if
(
!
inode
->
i_op
||
!
inode
->
i_op
->
lookup
)
break
;
if
(
f
ollow
&
FOLLOW
_CONTINUE
)
if
(
f
lags
&
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
;
...
...
fs/nfs/dir.c
View file @
d13a7654
...
...
@@ -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
;
...
...
fs/nfs/inode.c
View file @
d13a7654
...
...
@@ -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
);
...
...
fs/proc/mem.c
View file @
d13a7654
...
...
@@ -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
;
...
...
fs/super.c
View file @
d13a7654
...
...
@@ -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
;
}
...
...
fs/umsdos/dir.c
View file @
d13a7654
...
...
@@ -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
;
}
...
...
fs/umsdos/emd.c
View file @
d13a7654
...
...
@@ -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
...
...
fs/umsdos/inode.c
View file @
d13a7654
...
...
@@ -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 access
ed, 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
=
...
...
fs/umsdos/ioctl.c
View file @
d13a7654
...
...
@@ -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 mangle
d
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
;
}
...
...
fs/umsdos/namei.c
View file @
d13a7654
...
...
@@ -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
;
...
...
fs/umsdos/rdir.c
View file @
d13a7654
...
...
@@ -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
;
}
...
...
include/linux/ext2_fs.h
View file @
d13a7654
...
...
@@ -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
,
...
...
include/linux/quota.h
View file @
d13a7654
...
...
@@ -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
...
...
include/linux/sunrpc/auth.h
View file @
d13a7654
...
...
@@ -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
...
...
include/linux/sunrpc/clnt.h
View file @
d13a7654
...
...
@@ -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
...
...
include/linux/tcp.h
View file @
d13a7654
...
...
@@ -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
),
...
...
include/linux/umsdos_fs.p
View file @
d13a7654
...
...
@@ -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
);
include/linux/umsdos_fs_i.h
View file @
d13a7654
...
...
@@ -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
net/ipv4/tcp.c
View file @
d13a7654
...
...
@@ -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
);
}
...
...
net/sunrpc/auth_unix.c
View file @
d13a7654
...
...
@@ -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
);
...
...
net/sunrpc/clnt.c
View file @
d13a7654
...
...
@@ -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
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment