Skip to content

Commit 2cbe5c7

Browse files
Mikulas Patockatorvalds
Mikulas Patocka
authored andcommitted
hpfs: remember free space
Previously, hpfs scanned all bitmaps each time the user asked for free space using statfs. This patch changes it so that hpfs scans the bitmaps only once, remembes the free space and on next invocation of statfs it returns the value instantly. New versions of wine are hammering on the statfs syscall very heavily, making some games unplayable when they're stored on hpfs, with load times in minutes. This should be backported to the stable kernels because it fixes user-visible problem (excessive level load times in wine). Signed-off-by: Mikulas Patocka <[email protected]> Cc: [email protected] Signed-off-by: Linus Torvalds <[email protected]>
1 parent 602456b commit 2cbe5c7

File tree

3 files changed

+87
-10
lines changed

3 files changed

+87
-10
lines changed

fs/hpfs/alloc.c

+64-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,58 @@
88

99
#include "hpfs_fn.h"
1010

11+
static void hpfs_claim_alloc(struct super_block *s, secno sec)
12+
{
13+
struct hpfs_sb_info *sbi = hpfs_sb(s);
14+
if (sbi->sb_n_free != (unsigned)-1) {
15+
if (unlikely(!sbi->sb_n_free)) {
16+
hpfs_error(s, "free count underflow, allocating sector %08x", sec);
17+
sbi->sb_n_free = -1;
18+
return;
19+
}
20+
sbi->sb_n_free--;
21+
}
22+
}
23+
24+
static void hpfs_claim_free(struct super_block *s, secno sec)
25+
{
26+
struct hpfs_sb_info *sbi = hpfs_sb(s);
27+
if (sbi->sb_n_free != (unsigned)-1) {
28+
if (unlikely(sbi->sb_n_free >= sbi->sb_fs_size)) {
29+
hpfs_error(s, "free count overflow, freeing sector %08x", sec);
30+
sbi->sb_n_free = -1;
31+
return;
32+
}
33+
sbi->sb_n_free++;
34+
}
35+
}
36+
37+
static void hpfs_claim_dirband_alloc(struct super_block *s, secno sec)
38+
{
39+
struct hpfs_sb_info *sbi = hpfs_sb(s);
40+
if (sbi->sb_n_free_dnodes != (unsigned)-1) {
41+
if (unlikely(!sbi->sb_n_free_dnodes)) {
42+
hpfs_error(s, "dirband free count underflow, allocating sector %08x", sec);
43+
sbi->sb_n_free_dnodes = -1;
44+
return;
45+
}
46+
sbi->sb_n_free_dnodes--;
47+
}
48+
}
49+
50+
static void hpfs_claim_dirband_free(struct super_block *s, secno sec)
51+
{
52+
struct hpfs_sb_info *sbi = hpfs_sb(s);
53+
if (sbi->sb_n_free_dnodes != (unsigned)-1) {
54+
if (unlikely(sbi->sb_n_free_dnodes >= sbi->sb_dirband_size / 4)) {
55+
hpfs_error(s, "dirband free count overflow, freeing sector %08x", sec);
56+
sbi->sb_n_free_dnodes = -1;
57+
return;
58+
}
59+
sbi->sb_n_free_dnodes++;
60+
}
61+
}
62+
1163
/*
1264
* Check if a sector is allocated in bitmap
1365
* This is really slow. Turned on only if chk==2
@@ -203,9 +255,15 @@ secno hpfs_alloc_sector(struct super_block *s, secno near, unsigned n, int forwa
203255
}
204256
sec = 0;
205257
ret:
258+
if (sec) {
259+
i = 0;
260+
do
261+
hpfs_claim_alloc(s, sec + i);
262+
while (unlikely(++i < n));
263+
}
206264
if (sec && f_p) {
207265
for (i = 0; i < forward; i++) {
208-
if (!hpfs_alloc_if_possible(s, sec + i + 1)) {
266+
if (!hpfs_alloc_if_possible(s, sec + n + i)) {
209267
hpfs_error(s, "Prealloc doesn't work! Wanted %d, allocated at %08x, can't allocate %d", forward, sec, i);
210268
sec = 0;
211269
break;
@@ -228,6 +286,7 @@ static secno alloc_in_dirband(struct super_block *s, secno near)
228286
nr >>= 2;
229287
sec = alloc_in_bmp(s, (~0x3fff) | nr, 1, 0);
230288
if (!sec) return 0;
289+
hpfs_claim_dirband_alloc(s, sec);
231290
return ((sec & 0x3fff) << 2) + sbi->sb_dirband_start;
232291
}
233292

@@ -242,6 +301,7 @@ int hpfs_alloc_if_possible(struct super_block *s, secno sec)
242301
bmp[(sec & 0x3fff) >> 5] &= cpu_to_le32(~(1 << (sec & 0x1f)));
243302
hpfs_mark_4buffers_dirty(&qbh);
244303
hpfs_brelse4(&qbh);
304+
hpfs_claim_alloc(s, sec);
245305
return 1;
246306
}
247307
hpfs_brelse4(&qbh);
@@ -275,6 +335,7 @@ void hpfs_free_sectors(struct super_block *s, secno sec, unsigned n)
275335
return;
276336
}
277337
bmp[(sec & 0x3fff) >> 5] |= cpu_to_le32(1 << (sec & 0x1f));
338+
hpfs_claim_free(s, sec);
278339
if (!--n) {
279340
hpfs_mark_4buffers_dirty(&qbh);
280341
hpfs_brelse4(&qbh);
@@ -359,14 +420,15 @@ void hpfs_free_dnode(struct super_block *s, dnode_secno dno)
359420
bmp[ssec >> 5] |= cpu_to_le32(1 << (ssec & 0x1f));
360421
hpfs_mark_4buffers_dirty(&qbh);
361422
hpfs_brelse4(&qbh);
423+
hpfs_claim_dirband_free(s, dno);
362424
}
363425
}
364426

365427
struct dnode *hpfs_alloc_dnode(struct super_block *s, secno near,
366428
dnode_secno *dno, struct quad_buffer_head *qbh)
367429
{
368430
struct dnode *d;
369-
if (hpfs_count_one_bitmap(s, hpfs_sb(s)->sb_dmap) > FREE_DNODES_ADD) {
431+
if (hpfs_get_free_dnodes(s) > FREE_DNODES_ADD) {
370432
if (!(*dno = alloc_in_dirband(s, near)))
371433
if (!(*dno = hpfs_alloc_sector(s, near, 4, 0))) return NULL;
372434
} else {

fs/hpfs/hpfs_fn.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ static inline struct hpfs_sb_info *hpfs_sb(struct super_block *sb)
312312
__printf(2, 3)
313313
void hpfs_error(struct super_block *, const char *, ...);
314314
int hpfs_stop_cycles(struct super_block *, int, int *, int *, char *);
315-
unsigned hpfs_count_one_bitmap(struct super_block *, secno);
315+
unsigned hpfs_get_free_dnodes(struct super_block *);
316316

317317
/*
318318
* local time (HPFS) to GMT (Unix)

fs/hpfs/super.c

+22-7
Original file line numberDiff line numberDiff line change
@@ -121,15 +121,15 @@ static void hpfs_put_super(struct super_block *s)
121121
call_rcu(&hpfs_sb(s)->rcu, lazy_free_sbi);
122122
}
123123

124-
unsigned hpfs_count_one_bitmap(struct super_block *s, secno secno)
124+
static unsigned hpfs_count_one_bitmap(struct super_block *s, secno secno)
125125
{
126126
struct quad_buffer_head qbh;
127127
unsigned long *bits;
128128
unsigned count;
129129

130130
bits = hpfs_map_4sectors(s, secno, &qbh, 0);
131131
if (!bits)
132-
return 0;
132+
return (unsigned)-1;
133133
count = bitmap_weight(bits, 2048 * BITS_PER_BYTE);
134134
hpfs_brelse4(&qbh);
135135
return count;
@@ -144,30 +144,45 @@ static unsigned count_bitmaps(struct super_block *s)
144144
hpfs_prefetch_bitmap(s, n);
145145
}
146146
for (n = 0; n < n_bands; n++) {
147+
unsigned c;
147148
hpfs_prefetch_bitmap(s, n + COUNT_RD_AHEAD);
148-
count += hpfs_count_one_bitmap(s, le32_to_cpu(hpfs_sb(s)->sb_bmp_dir[n]));
149+
c = hpfs_count_one_bitmap(s, le32_to_cpu(hpfs_sb(s)->sb_bmp_dir[n]));
150+
if (c != (unsigned)-1)
151+
count += c;
149152
}
150153
return count;
151154
}
152155

156+
unsigned hpfs_get_free_dnodes(struct super_block *s)
157+
{
158+
struct hpfs_sb_info *sbi = hpfs_sb(s);
159+
if (sbi->sb_n_free_dnodes == (unsigned)-1) {
160+
unsigned c = hpfs_count_one_bitmap(s, sbi->sb_dmap);
161+
if (c == (unsigned)-1)
162+
return 0;
163+
sbi->sb_n_free_dnodes = c;
164+
}
165+
return sbi->sb_n_free_dnodes;
166+
}
167+
153168
static int hpfs_statfs(struct dentry *dentry, struct kstatfs *buf)
154169
{
155170
struct super_block *s = dentry->d_sb;
156171
struct hpfs_sb_info *sbi = hpfs_sb(s);
157172
u64 id = huge_encode_dev(s->s_bdev->bd_dev);
173+
158174
hpfs_lock(s);
159175

160-
/*if (sbi->sb_n_free == -1) {*/
176+
if (sbi->sb_n_free == (unsigned)-1)
161177
sbi->sb_n_free = count_bitmaps(s);
162-
sbi->sb_n_free_dnodes = hpfs_count_one_bitmap(s, sbi->sb_dmap);
163-
/*}*/
178+
164179
buf->f_type = s->s_magic;
165180
buf->f_bsize = 512;
166181
buf->f_blocks = sbi->sb_fs_size;
167182
buf->f_bfree = sbi->sb_n_free;
168183
buf->f_bavail = sbi->sb_n_free;
169184
buf->f_files = sbi->sb_dirband_size / 4;
170-
buf->f_ffree = sbi->sb_n_free_dnodes;
185+
buf->f_ffree = hpfs_get_free_dnodes(s);
171186
buf->f_fsid.val[0] = (u32)id;
172187
buf->f_fsid.val[1] = (u32)(id >> 32);
173188
buf->f_namelen = 254;

0 commit comments

Comments
 (0)