Skip to content

Commit 419a6e5

Browse files
Russell KingAl Viro
authored andcommitted
fs/adfs: dir: add generic directory reading
Both directory formats code the mechanics of fetching the directory buffers using their own implementations. Consolidate these into one implementation. Signed-off-by: Russell King <[email protected]> Signed-off-by: Al Viro <[email protected]>
1 parent a317120 commit 419a6e5

File tree

4 files changed

+74
-77
lines changed

4 files changed

+74
-77
lines changed

fs/adfs/adfs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,8 @@ int adfs_dir_copyfrom(void *dst, struct adfs_dir *dir, unsigned int offset,
170170
int adfs_dir_copyto(struct adfs_dir *dir, unsigned int offset, const void *src,
171171
size_t len);
172172
void adfs_dir_relse(struct adfs_dir *dir);
173+
int adfs_dir_read_buffers(struct super_block *sb, u32 indaddr,
174+
unsigned int size, struct adfs_dir *dir);
173175
void adfs_object_fixup(struct adfs_dir *dir, struct object_info *obj);
174176
extern int adfs_dir_update(struct super_block *sb, struct object_info *obj,
175177
int wait);

fs/adfs/dir.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,55 @@ void adfs_dir_relse(struct adfs_dir *dir)
7878
dir->sb = NULL;
7979
}
8080

81+
int adfs_dir_read_buffers(struct super_block *sb, u32 indaddr,
82+
unsigned int size, struct adfs_dir *dir)
83+
{
84+
struct buffer_head **bhs;
85+
unsigned int i, num;
86+
int block;
87+
88+
num = ALIGN(size, sb->s_blocksize) >> sb->s_blocksize_bits;
89+
if (num > ARRAY_SIZE(dir->bh)) {
90+
/* We only allow one extension */
91+
if (dir->bhs != dir->bh)
92+
return -EINVAL;
93+
94+
bhs = kcalloc(num, sizeof(*bhs), GFP_KERNEL);
95+
if (!bhs)
96+
return -ENOMEM;
97+
98+
if (dir->nr_buffers)
99+
memcpy(bhs, dir->bhs, dir->nr_buffers * sizeof(*bhs));
100+
101+
dir->bhs = bhs;
102+
}
103+
104+
for (i = dir->nr_buffers; i < num; i++) {
105+
block = __adfs_block_map(sb, indaddr, i);
106+
if (!block) {
107+
adfs_error(sb, "dir %06x has a hole at offset %u",
108+
indaddr, i);
109+
goto error;
110+
}
111+
112+
dir->bhs[i] = sb_bread(sb, block);
113+
if (!dir->bhs[i]) {
114+
adfs_error(sb,
115+
"dir %06x failed read at offset %u, mapped block 0x%08x",
116+
indaddr, i, block);
117+
goto error;
118+
}
119+
120+
dir->nr_buffers++;
121+
}
122+
return 0;
123+
124+
error:
125+
adfs_dir_relse(dir);
126+
127+
return -EIO;
128+
}
129+
81130
static int adfs_dir_read(struct super_block *sb, u32 indaddr,
82131
unsigned int size, struct adfs_dir *dir)
83132
{

fs/adfs/dir_f.c

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ static int adfs_dir_read(struct super_block *sb, u32 indaddr,
126126
unsigned int size, struct adfs_dir *dir)
127127
{
128128
const unsigned int blocksize_bits = sb->s_blocksize_bits;
129-
int blk;
129+
int ret;
130130

131131
/*
132132
* Directories which are not a multiple of 2048 bytes
@@ -135,24 +135,9 @@ static int adfs_dir_read(struct super_block *sb, u32 indaddr,
135135
if (size & 2047)
136136
goto bad_dir;
137137

138-
size >>= blocksize_bits;
139-
140-
for (blk = 0; blk < size; blk++) {
141-
int phys;
142-
143-
phys = __adfs_block_map(sb, indaddr, blk);
144-
if (!phys) {
145-
adfs_error(sb, "dir %06x has a hole at offset %d",
146-
indaddr, blk);
147-
goto release_buffers;
148-
}
149-
150-
dir->bh[blk] = sb_bread(sb, phys);
151-
if (!dir->bh[blk])
152-
goto release_buffers;
153-
154-
dir->nr_buffers += 1;
155-
}
138+
ret = adfs_dir_read_buffers(sb, indaddr, size, dir);
139+
if (ret)
140+
return ret;
156141

157142
memcpy(&dir->dirhead, bufoff(dir->bh, 0), sizeof(dir->dirhead));
158143
memcpy(&dir->dirtail, bufoff(dir->bh, 2007), sizeof(dir->dirtail));
@@ -172,7 +157,6 @@ static int adfs_dir_read(struct super_block *sb, u32 indaddr,
172157

173158
bad_dir:
174159
adfs_error(sb, "dir %06x is corrupted", indaddr);
175-
release_buffers:
176160
adfs_dir_relse(dir);
177161

178162
return -EIO;

fs/adfs/dir_fplus.c

Lines changed: 19 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -4,87 +4,49 @@
44
*
55
* Copyright (C) 1997-1999 Russell King
66
*/
7-
#include <linux/slab.h>
87
#include "adfs.h"
98
#include "dir_fplus.h"
109

11-
static int
12-
adfs_fplus_read(struct super_block *sb, unsigned int id, unsigned int sz, struct adfs_dir *dir)
10+
static int adfs_fplus_read(struct super_block *sb, u32 indaddr,
11+
unsigned int size, struct adfs_dir *dir)
1312
{
1413
struct adfs_bigdirheader *h;
1514
struct adfs_bigdirtail *t;
16-
unsigned long block;
17-
unsigned int blk, size;
18-
int ret = -EIO;
19-
20-
block = __adfs_block_map(sb, id, 0);
21-
if (!block) {
22-
adfs_error(sb, "dir object %X has a hole at offset 0", id);
23-
goto out;
24-
}
15+
unsigned int dirsize;
16+
int ret;
2517

26-
dir->bhs[0] = sb_bread(sb, block);
27-
if (!dir->bhs[0])
28-
goto out;
29-
dir->nr_buffers += 1;
18+
/* Read first buffer */
19+
ret = adfs_dir_read_buffers(sb, indaddr, sb->s_blocksize, dir);
20+
if (ret)
21+
return ret;
3022

3123
h = (struct adfs_bigdirheader *)dir->bhs[0]->b_data;
32-
size = le32_to_cpu(h->bigdirsize);
33-
if (size != sz) {
24+
dirsize = le32_to_cpu(h->bigdirsize);
25+
if (dirsize != size) {
3426
adfs_msg(sb, KERN_WARNING,
35-
"directory header size %X does not match directory size %X",
36-
size, sz);
27+
"dir %06x header size %X does not match directory size %X",
28+
indaddr, dirsize, size);
3729
}
3830

3931
if (h->bigdirversion[0] != 0 || h->bigdirversion[1] != 0 ||
4032
h->bigdirversion[2] != 0 || size & 2047 ||
4133
h->bigdirstartname != cpu_to_le32(BIGDIRSTARTNAME)) {
42-
adfs_error(sb, "dir %06x has malformed header", id);
34+
adfs_error(sb, "dir %06x has malformed header", indaddr);
4335
goto out;
4436
}
4537

46-
size >>= sb->s_blocksize_bits;
47-
if (size > ARRAY_SIZE(dir->bh)) {
48-
/* this directory is too big for fixed bh set, must allocate */
49-
struct buffer_head **bhs =
50-
kcalloc(size, sizeof(struct buffer_head *),
51-
GFP_KERNEL);
52-
if (!bhs) {
53-
adfs_msg(sb, KERN_ERR,
54-
"not enough memory for dir object %X (%d blocks)",
55-
id, size);
56-
ret = -ENOMEM;
57-
goto out;
58-
}
59-
dir->bhs = bhs;
60-
/* copy over the pointer to the block that we've already read */
61-
dir->bhs[0] = dir->bh[0];
62-
}
63-
64-
for (blk = 1; blk < size; blk++) {
65-
block = __adfs_block_map(sb, id, blk);
66-
if (!block) {
67-
adfs_error(sb, "dir object %X has a hole at offset %d", id, blk);
68-
goto out;
69-
}
70-
71-
dir->bhs[blk] = sb_bread(sb, block);
72-
if (!dir->bhs[blk]) {
73-
adfs_error(sb, "dir object %x failed read for offset %d, mapped block %lX",
74-
id, blk, block);
75-
goto out;
76-
}
77-
78-
dir->nr_buffers += 1;
79-
}
38+
/* Read remaining buffers */
39+
ret = adfs_dir_read_buffers(sb, indaddr, dirsize, dir);
40+
if (ret)
41+
return ret;
8042

8143
t = (struct adfs_bigdirtail *)
82-
(dir->bhs[size - 1]->b_data + (sb->s_blocksize - 8));
44+
(dir->bhs[dir->nr_buffers - 1]->b_data + (sb->s_blocksize - 8));
8345

8446
if (t->bigdirendname != cpu_to_le32(BIGDIRENDNAME) ||
8547
t->bigdirendmasseq != h->startmasseq ||
8648
t->reserved[0] != 0 || t->reserved[1] != 0) {
87-
adfs_error(sb, "dir %06x has malformed tail", id);
49+
adfs_error(sb, "dir %06x has malformed tail", indaddr);
8850
goto out;
8951
}
9052

0 commit comments

Comments
 (0)