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
nexedi
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
Hide 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);
int
adfs_notify_change
(
struct
dentry
*
dentry
,
struct
iattr
*
attr
);
/* 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
);
/* Misc */
...
...
fs/adfs/dir.c
View file @
b918ced4
...
...
@@ -24,7 +24,7 @@
/*
* 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
adfs_readdir
(
struct
file
*
filp
,
void
*
dirent
,
filldir_t
filldir
)
...
...
fs/adfs/map.c
View file @
b918ced4
/*
* 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
* it under the terms of the GNU General Public License version 2 as
...
...
@@ -13,30 +13,64 @@
#include <linux/adfs_fs.h>
#include <linux/spinlock.h>
#include <asm/unaligned.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...
*/
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) \
({ \
unsigned long _v2, _frag; \
unsigned int _tmp; \
_tmp = _start >> 5; \
_frag = le32_to_cpu(_map[_tmp]); \
_v2 = le32_to_cpu(_map[_tmp + 1]); \
_tmp = start & 31; \
_frag = (_frag >> _tmp) | (_v2 << (32 - _tmp)); \
unsigned char *_m = _map + (_start >> 3); \
u32 _frag = get_unaligned((u32 *)_m); \
_frag >>= (_start & 7); \
_frag & _idmask; \
})
/*
* return the map bit offset of the fragment frag_id in
* the zone dm.
* Note that the loop is optimised for best asm code -
* look at the output of:
* return the map bit offset of the fragment frag_id in the zone dm.
* Note that the loop is optimised for best asm code - look at the
* output of:
* gcc -D__KERNEL__ -O2 -I../../include -o - -S map.c
*/
static
int
...
...
@@ -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
mapsize
=
dm
->
dm_endbit
;
const
u
nsigned
int
idmask
=
(
1
<<
idlen
)
-
1
;
unsigned
long
*
map
=
((
unsigned
long
*
)
dm
->
dm_bh
->
b_data
)
+
1
;
const
u
32
idmask
=
(
1
<<
idlen
)
-
1
;
unsigned
char
*
map
=
dm
->
dm_bh
->
b_data
+
4
;
unsigned
int
start
=
dm
->
dm_startbit
;
unsigned
int
mapptr
;
u32
frag
;
do
{
unsigned
long
frag
;
frag
=
GET_FRAG_ID
(
map
,
start
,
idmask
);
mapptr
=
start
+
idlen
;
...
...
@@ -59,15 +92,17 @@ lookup_zone(const struct adfs_discmap *dm, const unsigned int idlen,
* 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
;
if
(
mapptr
>=
mapsize
)
goto
error
;
v
=
le32_to_cpu
(
_map
[
mapptr
>>
5
]);
}
mapptr
+=
1
+
ffz
(
~
v
2
);
mapptr
+=
1
+
ffz
(
~
v
);
}
if
(
frag
==
frag_id
)
...
...
@@ -75,8 +110,11 @@ lookup_zone(const struct adfs_discmap *dm, const unsigned int idlen,
again:
start
=
mapptr
;
}
while
(
mapptr
<
mapsize
);
return
-
1
;
error:
printk
(
KERN_ERR
"adfs: oversized fragment 0x%x at 0x%x-0x%x
\n
"
,
frag
,
start
,
mapptr
);
return
-
1
;
found:
...
...
@@ -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
idlen
=
asb
->
s_idlen
;
const
unsigned
int
frag_idlen
=
idlen
<=
15
?
idlen
:
15
;
const
u
nsigned
int
idmask
=
(
1
<<
frag_idlen
)
-
1
;
unsigned
long
*
map
=
(
unsigned
long
*
)
dm
->
dm_bh
->
b_data
;
const
u
32
idmask
=
(
1
<<
frag_idlen
)
-
1
;
unsigned
char
*
map
=
dm
->
dm_bh
->
b_data
;
unsigned
int
start
=
8
,
mapptr
;
u
nsigned
long
frag
;
u
32
frag
;
unsigned
long
total
=
0
;
/*
...
...
@@ -133,15 +171,17 @@ scan_free_map(struct adfs_sb_info *asb, struct adfs_discmap *dm)
* 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
;
if
(
mapptr
>=
mapsize
)
goto
error
;
v
=
le32_to_cpu
(
_map
[
mapptr
>>
5
]);
}
mapptr
+=
1
+
ffz
(
~
v
2
);
mapptr
+=
1
+
ffz
(
~
v
);
}
total
+=
mapptr
-
start
;
...
...
@@ -212,7 +252,9 @@ adfs_map_free(struct super_block *sb)
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
;
unsigned
int
zone
,
mapoff
;
...
...
@@ -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
);
}
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
);
return
0
;
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
);
return
0
;
}
fs/adfs/super.c
View file @
b918ced4
...
...
@@ -64,43 +64,9 @@ static int adfs_checkdiscrecord(struct adfs_discrecord *dr)
if
(
dr
->
disc_size_high
>>
dr
->
log2secsize
)
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] */
if
(
dr
->
idlen
>
19
)
return
1
;
#endif
#endif
/* reserved bytes should be zero */
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