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
b918ced4
Commit
b918ced4
authored
May 13, 2002
by
Russell King
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[ARM] ADFS updates/fixes.
Fixes lockup on SMP boxes, and fixes buggy map scanning code.
parent
34dc307a
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
73 additions
and
65 deletions
+73
-65
fs/adfs/adfs.h
fs/adfs/adfs.h
+1
-1
fs/adfs/dir.c
fs/adfs/dir.c
+1
-1
fs/adfs/map.c
fs/adfs/map.c
+71
-29
fs/adfs/super.c
fs/adfs/super.c
+0
-34
No files found.
fs/adfs/adfs.h
View file @
b918ced4
...
@@ -77,7 +77,7 @@ void adfs_write_inode(struct inode *inode,int unused);
...
@@ -77,7 +77,7 @@ void adfs_write_inode(struct inode *inode,int unused);
int
adfs_notify_change
(
struct
dentry
*
dentry
,
struct
iattr
*
attr
);
int
adfs_notify_change
(
struct
dentry
*
dentry
,
struct
iattr
*
attr
);
/* map.c */
/* map.c */
extern
int
adfs_map_lookup
(
struct
super_block
*
sb
,
int
frag_id
,
int
offset
);
extern
int
adfs_map_lookup
(
struct
super_block
*
sb
,
unsigned
int
frag_id
,
unsigned
int
offset
);
extern
unsigned
int
adfs_map_free
(
struct
super_block
*
sb
);
extern
unsigned
int
adfs_map_free
(
struct
super_block
*
sb
);
/* Misc */
/* Misc */
...
...
fs/adfs/dir.c
View file @
b918ced4
...
@@ -24,7 +24,7 @@
...
@@ -24,7 +24,7 @@
/*
/*
* For future. This should probably be per-directory.
* For future. This should probably be per-directory.
*/
*/
static
rwlock_t
adfs_dir_lock
;
static
rwlock_t
adfs_dir_lock
=
RW_LOCK_UNLOCKED
;
static
int
static
int
adfs_readdir
(
struct
file
*
filp
,
void
*
dirent
,
filldir_t
filldir
)
adfs_readdir
(
struct
file
*
filp
,
void
*
dirent
,
filldir_t
filldir
)
...
...
fs/adfs/map.c
View file @
b918ced4
/*
/*
* linux/fs/adfs/map.c
* linux/fs/adfs/map.c
*
*
* Copyright (C) 1997-
1999
Russell King
* Copyright (C) 1997-
2002
Russell King
*
*
* This program is free software; you can redistribute it and/or modify
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* it under the terms of the GNU General Public License version 2 as
...
@@ -13,30 +13,64 @@
...
@@ -13,30 +13,64 @@
#include <linux/adfs_fs.h>
#include <linux/adfs_fs.h>
#include <linux/spinlock.h>
#include <linux/spinlock.h>
#include <asm/unaligned.h>
#include "adfs.h"
#include "adfs.h"
/*
* The ADFS map is basically a set of sectors. Each sector is called a
* zone which contains a bitstream made up of variable sized fragments.
* Each bit refers to a set of bytes in the filesystem, defined by
* log2bpmb. This may be larger or smaller than the sector size, but
* the overall size it describes will always be a round number of
* sectors. A fragment id is always idlen bits long.
*
* < idlen > < n > <1>
* +---------+-------//---------+---+
* | frag id | 0000....000000 | 1 |
* +---------+-------//---------+---+
*
* The physical disk space used by a fragment is taken from the start of
* the fragment id up to and including the '1' bit - ie, idlen + n + 1
* bits.
*
* A fragment id can be repeated multiple times in the whole map for
* large or fragmented files. The first map zone a fragment starts in
* is given by fragment id / ids_per_zone - this allows objects to start
* from any zone on the disk.
*
* Free space is described by a linked list of fragments. Each free
* fragment describes free space in the same way as the other fragments,
* however, the frag id specifies an offset (in map bits) from the end
* of this fragment to the start of the next free fragment.
*
* Objects stored on the disk are allocated object ids (we use these as
* our inode numbers.) Object ids contain a fragment id and an optional
* offset. This allows a directory fragment to contain small files
* associated with that directory.
*/
/*
/*
* For the future...
* For the future...
*/
*/
static
rwlock_t
adfs_map_lock
;
static
rwlock_t
adfs_map_lock
=
RW_LOCK_UNLOCKED
;
/*
* This is fun. We need to load up to 19 bits from the map at an
* arbitary bit alignment. (We're limited to 19 bits by F+ version 2).
*/
#define GET_FRAG_ID(_map,_start,_idmask) \
#define GET_FRAG_ID(_map,_start,_idmask) \
({ \
({ \
unsigned long _v2, _frag; \
unsigned char *_m = _map + (_start >> 3); \
unsigned int _tmp; \
u32 _frag = get_unaligned((u32 *)_m); \
_tmp = _start >> 5; \
_frag >>= (_start & 7); \
_frag = le32_to_cpu(_map[_tmp]); \
_v2 = le32_to_cpu(_map[_tmp + 1]); \
_tmp = start & 31; \
_frag = (_frag >> _tmp) | (_v2 << (32 - _tmp)); \
_frag & _idmask; \
_frag & _idmask; \
})
})
/*
/*
* return the map bit offset of the fragment frag_id in
* return the map bit offset of the fragment frag_id in the zone dm.
* the zone dm.
* Note that the loop is optimised for best asm code - look at the
* Note that the loop is optimised for best asm code -
* output of:
* look at the output of:
* gcc -D__KERNEL__ -O2 -I../../include -o - -S map.c
* gcc -D__KERNEL__ -O2 -I../../include -o - -S map.c
*/
*/
static
int
static
int
...
@@ -44,14 +78,13 @@ lookup_zone(const struct adfs_discmap *dm, const unsigned int idlen,
...
@@ -44,14 +78,13 @@ lookup_zone(const struct adfs_discmap *dm, const unsigned int idlen,
const
unsigned
int
frag_id
,
unsigned
int
*
offset
)
const
unsigned
int
frag_id
,
unsigned
int
*
offset
)
{
{
const
unsigned
int
mapsize
=
dm
->
dm_endbit
;
const
unsigned
int
mapsize
=
dm
->
dm_endbit
;
const
u
nsigned
int
idmask
=
(
1
<<
idlen
)
-
1
;
const
u
32
idmask
=
(
1
<<
idlen
)
-
1
;
unsigned
long
*
map
=
((
unsigned
long
*
)
dm
->
dm_bh
->
b_data
)
+
1
;
unsigned
char
*
map
=
dm
->
dm_bh
->
b_data
+
4
;
unsigned
int
start
=
dm
->
dm_startbit
;
unsigned
int
start
=
dm
->
dm_startbit
;
unsigned
int
mapptr
;
unsigned
int
mapptr
;
u32
frag
;
do
{
do
{
unsigned
long
frag
;
frag
=
GET_FRAG_ID
(
map
,
start
,
idmask
);
frag
=
GET_FRAG_ID
(
map
,
start
,
idmask
);
mapptr
=
start
+
idlen
;
mapptr
=
start
+
idlen
;
...
@@ -59,15 +92,17 @@ lookup_zone(const struct adfs_discmap *dm, const unsigned int idlen,
...
@@ -59,15 +92,17 @@ lookup_zone(const struct adfs_discmap *dm, const unsigned int idlen,
* find end of fragment
* find end of fragment
*/
*/
{
{
u
nsigned
long
v2
;
u
32
v
,
*
_map
=
(
u32
*
)
map
;
while
((
v2
=
map
[
mapptr
>>
5
]
>>
(
mapptr
&
31
))
==
0
)
{
v
=
le32_to_cpu
(
_map
[
mapptr
>>
5
])
>>
(
mapptr
&
31
);
while
(
v
==
0
)
{
mapptr
=
(
mapptr
&
~
31
)
+
32
;
mapptr
=
(
mapptr
&
~
31
)
+
32
;
if
(
mapptr
>=
mapsize
)
if
(
mapptr
>=
mapsize
)
goto
error
;
goto
error
;
v
=
le32_to_cpu
(
_map
[
mapptr
>>
5
]);
}
}
mapptr
+=
1
+
ffz
(
~
v
2
);
mapptr
+=
1
+
ffz
(
~
v
);
}
}
if
(
frag
==
frag_id
)
if
(
frag
==
frag_id
)
...
@@ -75,8 +110,11 @@ lookup_zone(const struct adfs_discmap *dm, const unsigned int idlen,
...
@@ -75,8 +110,11 @@ lookup_zone(const struct adfs_discmap *dm, const unsigned int idlen,
again:
again:
start
=
mapptr
;
start
=
mapptr
;
}
while
(
mapptr
<
mapsize
);
}
while
(
mapptr
<
mapsize
);
return
-
1
;
error:
error:
printk
(
KERN_ERR
"adfs: oversized fragment 0x%x at 0x%x-0x%x
\n
"
,
frag
,
start
,
mapptr
);
return
-
1
;
return
-
1
;
found:
found:
...
@@ -102,10 +140,10 @@ scan_free_map(struct adfs_sb_info *asb, struct adfs_discmap *dm)
...
@@ -102,10 +140,10 @@ scan_free_map(struct adfs_sb_info *asb, struct adfs_discmap *dm)
const
unsigned
int
mapsize
=
dm
->
dm_endbit
+
32
;
const
unsigned
int
mapsize
=
dm
->
dm_endbit
+
32
;
const
unsigned
int
idlen
=
asb
->
s_idlen
;
const
unsigned
int
idlen
=
asb
->
s_idlen
;
const
unsigned
int
frag_idlen
=
idlen
<=
15
?
idlen
:
15
;
const
unsigned
int
frag_idlen
=
idlen
<=
15
?
idlen
:
15
;
const
u
nsigned
int
idmask
=
(
1
<<
frag_idlen
)
-
1
;
const
u
32
idmask
=
(
1
<<
frag_idlen
)
-
1
;
unsigned
long
*
map
=
(
unsigned
long
*
)
dm
->
dm_bh
->
b_data
;
unsigned
char
*
map
=
dm
->
dm_bh
->
b_data
;
unsigned
int
start
=
8
,
mapptr
;
unsigned
int
start
=
8
,
mapptr
;
u
nsigned
long
frag
;
u
32
frag
;
unsigned
long
total
=
0
;
unsigned
long
total
=
0
;
/*
/*
...
@@ -133,15 +171,17 @@ scan_free_map(struct adfs_sb_info *asb, struct adfs_discmap *dm)
...
@@ -133,15 +171,17 @@ scan_free_map(struct adfs_sb_info *asb, struct adfs_discmap *dm)
* find end of fragment
* find end of fragment
*/
*/
{
{
u
nsigned
long
v2
;
u
32
v
,
*
_map
=
(
u32
*
)
map
;
while
((
v2
=
map
[
mapptr
>>
5
]
>>
(
mapptr
&
31
))
==
0
)
{
v
=
le32_to_cpu
(
_map
[
mapptr
>>
5
])
>>
(
mapptr
&
31
);
while
(
v
==
0
)
{
mapptr
=
(
mapptr
&
~
31
)
+
32
;
mapptr
=
(
mapptr
&
~
31
)
+
32
;
if
(
mapptr
>=
mapsize
)
if
(
mapptr
>=
mapsize
)
goto
error
;
goto
error
;
v
=
le32_to_cpu
(
_map
[
mapptr
>>
5
]);
}
}
mapptr
+=
1
+
ffz
(
~
v
2
);
mapptr
+=
1
+
ffz
(
~
v
);
}
}
total
+=
mapptr
-
start
;
total
+=
mapptr
-
start
;
...
@@ -212,7 +252,9 @@ adfs_map_free(struct super_block *sb)
...
@@ -212,7 +252,9 @@ adfs_map_free(struct super_block *sb)
return
signed_asl
(
total
,
asb
->
s_map2blk
);
return
signed_asl
(
total
,
asb
->
s_map2blk
);
}
}
int
adfs_map_lookup
(
struct
super_block
*
sb
,
int
frag_id
,
int
offset
)
int
adfs_map_lookup
(
struct
super_block
*
sb
,
unsigned
int
frag_id
,
unsigned
int
offset
)
{
{
struct
adfs_sb_info
*
asb
=
&
sb
->
u
.
adfs_sb
;
struct
adfs_sb_info
*
asb
=
&
sb
->
u
.
adfs_sb
;
unsigned
int
zone
,
mapoff
;
unsigned
int
zone
,
mapoff
;
...
@@ -245,12 +287,12 @@ int adfs_map_lookup (struct super_block *sb, int frag_id, int offset)
...
@@ -245,12 +287,12 @@ int adfs_map_lookup (struct super_block *sb, int frag_id, int offset)
return
secoff
+
signed_asl
(
result
,
asb
->
s_map2blk
);
return
secoff
+
signed_asl
(
result
,
asb
->
s_map2blk
);
}
}
adfs_error
(
sb
,
"fragment
%04X
at offset %d not found in map"
,
adfs_error
(
sb
,
"fragment
0x%04x
at offset %d not found in map"
,
frag_id
,
offset
);
frag_id
,
offset
);
return
0
;
return
0
;
bad_fragment:
bad_fragment:
adfs_error
(
sb
,
"
fragment %X is invalid
(zone = %d, max = %d)"
,
adfs_error
(
sb
,
"
invalid fragment 0x%04x
(zone = %d, max = %d)"
,
frag_id
,
zone
,
asb
->
s_map_size
);
frag_id
,
zone
,
asb
->
s_map_size
);
return
0
;
return
0
;
}
}
fs/adfs/super.c
View file @
b918ced4
...
@@ -64,43 +64,9 @@ static int adfs_checkdiscrecord(struct adfs_discrecord *dr)
...
@@ -64,43 +64,9 @@ static int adfs_checkdiscrecord(struct adfs_discrecord *dr)
if
(
dr
->
disc_size_high
>>
dr
->
log2secsize
)
if
(
dr
->
disc_size_high
>>
dr
->
log2secsize
)
return
1
;
return
1
;
/*
* The following checks are not required for F+
* stage 1.
*/
#if 0
/* idlen must be smaller be no greater than 15 */
if (dr->idlen > 15)
return 1;
/* nzones must be less than 128 for the root
* directory to be addressable
*/
if (dr->nzones >= 128 && dr->nzones_high == 0)
return 1;
/* root must be of the form 0x2.. */
if ((le32_to_cpu(dr->root) & 0xffffff00) != 0x00000200)
return 1;
#else
/*
* Stage 2 F+ does not require the following check
*/
#if 0
/* idlen must be no greater than 16 v2 [1.0] */
if (dr->idlen > 16)
return 1;
/* we can't handle F+ discs yet */
if (dr->format_version || dr->root_size)
return 1;
#else
/* idlen must be no greater than 19 v2 [1.0] */
/* idlen must be no greater than 19 v2 [1.0] */
if
(
dr
->
idlen
>
19
)
if
(
dr
->
idlen
>
19
)
return
1
;
return
1
;
#endif
#endif
/* reserved bytes should be zero */
/* reserved bytes should be zero */
for
(
i
=
0
;
i
<
sizeof
(
dr
->
unused52
);
i
++
)
for
(
i
=
0
;
i
<
sizeof
(
dr
->
unused52
);
i
++
)
...
...
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