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 <mikulas@artax.karlin.mff.cuni.cz> Cc: stable@vger.kernel.org Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
602456bf16
commit
2cbe5c76fc
3 changed files with 87 additions and 10 deletions
|
@ -8,6 +8,58 @@
|
||||||
|
|
||||||
#include "hpfs_fn.h"
|
#include "hpfs_fn.h"
|
||||||
|
|
||||||
|
static void hpfs_claim_alloc(struct super_block *s, secno sec)
|
||||||
|
{
|
||||||
|
struct hpfs_sb_info *sbi = hpfs_sb(s);
|
||||||
|
if (sbi->sb_n_free != (unsigned)-1) {
|
||||||
|
if (unlikely(!sbi->sb_n_free)) {
|
||||||
|
hpfs_error(s, "free count underflow, allocating sector %08x", sec);
|
||||||
|
sbi->sb_n_free = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sbi->sb_n_free--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hpfs_claim_free(struct super_block *s, secno sec)
|
||||||
|
{
|
||||||
|
struct hpfs_sb_info *sbi = hpfs_sb(s);
|
||||||
|
if (sbi->sb_n_free != (unsigned)-1) {
|
||||||
|
if (unlikely(sbi->sb_n_free >= sbi->sb_fs_size)) {
|
||||||
|
hpfs_error(s, "free count overflow, freeing sector %08x", sec);
|
||||||
|
sbi->sb_n_free = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sbi->sb_n_free++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hpfs_claim_dirband_alloc(struct super_block *s, secno sec)
|
||||||
|
{
|
||||||
|
struct hpfs_sb_info *sbi = hpfs_sb(s);
|
||||||
|
if (sbi->sb_n_free_dnodes != (unsigned)-1) {
|
||||||
|
if (unlikely(!sbi->sb_n_free_dnodes)) {
|
||||||
|
hpfs_error(s, "dirband free count underflow, allocating sector %08x", sec);
|
||||||
|
sbi->sb_n_free_dnodes = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sbi->sb_n_free_dnodes--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hpfs_claim_dirband_free(struct super_block *s, secno sec)
|
||||||
|
{
|
||||||
|
struct hpfs_sb_info *sbi = hpfs_sb(s);
|
||||||
|
if (sbi->sb_n_free_dnodes != (unsigned)-1) {
|
||||||
|
if (unlikely(sbi->sb_n_free_dnodes >= sbi->sb_dirband_size / 4)) {
|
||||||
|
hpfs_error(s, "dirband free count overflow, freeing sector %08x", sec);
|
||||||
|
sbi->sb_n_free_dnodes = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sbi->sb_n_free_dnodes++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if a sector is allocated in bitmap
|
* Check if a sector is allocated in bitmap
|
||||||
* This is really slow. Turned on only if chk==2
|
* 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
|
||||||
}
|
}
|
||||||
sec = 0;
|
sec = 0;
|
||||||
ret:
|
ret:
|
||||||
|
if (sec) {
|
||||||
|
i = 0;
|
||||||
|
do
|
||||||
|
hpfs_claim_alloc(s, sec + i);
|
||||||
|
while (unlikely(++i < n));
|
||||||
|
}
|
||||||
if (sec && f_p) {
|
if (sec && f_p) {
|
||||||
for (i = 0; i < forward; i++) {
|
for (i = 0; i < forward; i++) {
|
||||||
if (!hpfs_alloc_if_possible(s, sec + i + 1)) {
|
if (!hpfs_alloc_if_possible(s, sec + n + i)) {
|
||||||
hpfs_error(s, "Prealloc doesn't work! Wanted %d, allocated at %08x, can't allocate %d", forward, sec, i);
|
hpfs_error(s, "Prealloc doesn't work! Wanted %d, allocated at %08x, can't allocate %d", forward, sec, i);
|
||||||
sec = 0;
|
sec = 0;
|
||||||
break;
|
break;
|
||||||
|
@ -228,6 +286,7 @@ static secno alloc_in_dirband(struct super_block *s, secno near)
|
||||||
nr >>= 2;
|
nr >>= 2;
|
||||||
sec = alloc_in_bmp(s, (~0x3fff) | nr, 1, 0);
|
sec = alloc_in_bmp(s, (~0x3fff) | nr, 1, 0);
|
||||||
if (!sec) return 0;
|
if (!sec) return 0;
|
||||||
|
hpfs_claim_dirband_alloc(s, sec);
|
||||||
return ((sec & 0x3fff) << 2) + sbi->sb_dirband_start;
|
return ((sec & 0x3fff) << 2) + sbi->sb_dirband_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,6 +301,7 @@ int hpfs_alloc_if_possible(struct super_block *s, secno sec)
|
||||||
bmp[(sec & 0x3fff) >> 5] &= cpu_to_le32(~(1 << (sec & 0x1f)));
|
bmp[(sec & 0x3fff) >> 5] &= cpu_to_le32(~(1 << (sec & 0x1f)));
|
||||||
hpfs_mark_4buffers_dirty(&qbh);
|
hpfs_mark_4buffers_dirty(&qbh);
|
||||||
hpfs_brelse4(&qbh);
|
hpfs_brelse4(&qbh);
|
||||||
|
hpfs_claim_alloc(s, sec);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
hpfs_brelse4(&qbh);
|
hpfs_brelse4(&qbh);
|
||||||
|
@ -275,6 +335,7 @@ void hpfs_free_sectors(struct super_block *s, secno sec, unsigned n)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bmp[(sec & 0x3fff) >> 5] |= cpu_to_le32(1 << (sec & 0x1f));
|
bmp[(sec & 0x3fff) >> 5] |= cpu_to_le32(1 << (sec & 0x1f));
|
||||||
|
hpfs_claim_free(s, sec);
|
||||||
if (!--n) {
|
if (!--n) {
|
||||||
hpfs_mark_4buffers_dirty(&qbh);
|
hpfs_mark_4buffers_dirty(&qbh);
|
||||||
hpfs_brelse4(&qbh);
|
hpfs_brelse4(&qbh);
|
||||||
|
@ -359,6 +420,7 @@ void hpfs_free_dnode(struct super_block *s, dnode_secno dno)
|
||||||
bmp[ssec >> 5] |= cpu_to_le32(1 << (ssec & 0x1f));
|
bmp[ssec >> 5] |= cpu_to_le32(1 << (ssec & 0x1f));
|
||||||
hpfs_mark_4buffers_dirty(&qbh);
|
hpfs_mark_4buffers_dirty(&qbh);
|
||||||
hpfs_brelse4(&qbh);
|
hpfs_brelse4(&qbh);
|
||||||
|
hpfs_claim_dirband_free(s, dno);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,7 +428,7 @@ struct dnode *hpfs_alloc_dnode(struct super_block *s, secno near,
|
||||||
dnode_secno *dno, struct quad_buffer_head *qbh)
|
dnode_secno *dno, struct quad_buffer_head *qbh)
|
||||||
{
|
{
|
||||||
struct dnode *d;
|
struct dnode *d;
|
||||||
if (hpfs_count_one_bitmap(s, hpfs_sb(s)->sb_dmap) > FREE_DNODES_ADD) {
|
if (hpfs_get_free_dnodes(s) > FREE_DNODES_ADD) {
|
||||||
if (!(*dno = alloc_in_dirband(s, near)))
|
if (!(*dno = alloc_in_dirband(s, near)))
|
||||||
if (!(*dno = hpfs_alloc_sector(s, near, 4, 0))) return NULL;
|
if (!(*dno = hpfs_alloc_sector(s, near, 4, 0))) return NULL;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -312,7 +312,7 @@ static inline struct hpfs_sb_info *hpfs_sb(struct super_block *sb)
|
||||||
__printf(2, 3)
|
__printf(2, 3)
|
||||||
void hpfs_error(struct super_block *, const char *, ...);
|
void hpfs_error(struct super_block *, const char *, ...);
|
||||||
int hpfs_stop_cycles(struct super_block *, int, int *, int *, char *);
|
int hpfs_stop_cycles(struct super_block *, int, int *, int *, char *);
|
||||||
unsigned hpfs_count_one_bitmap(struct super_block *, secno);
|
unsigned hpfs_get_free_dnodes(struct super_block *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* local time (HPFS) to GMT (Unix)
|
* local time (HPFS) to GMT (Unix)
|
||||||
|
|
|
@ -121,7 +121,7 @@ static void hpfs_put_super(struct super_block *s)
|
||||||
call_rcu(&hpfs_sb(s)->rcu, lazy_free_sbi);
|
call_rcu(&hpfs_sb(s)->rcu, lazy_free_sbi);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned hpfs_count_one_bitmap(struct super_block *s, secno secno)
|
static unsigned hpfs_count_one_bitmap(struct super_block *s, secno secno)
|
||||||
{
|
{
|
||||||
struct quad_buffer_head qbh;
|
struct quad_buffer_head qbh;
|
||||||
unsigned long *bits;
|
unsigned long *bits;
|
||||||
|
@ -129,7 +129,7 @@ unsigned hpfs_count_one_bitmap(struct super_block *s, secno secno)
|
||||||
|
|
||||||
bits = hpfs_map_4sectors(s, secno, &qbh, 0);
|
bits = hpfs_map_4sectors(s, secno, &qbh, 0);
|
||||||
if (!bits)
|
if (!bits)
|
||||||
return 0;
|
return (unsigned)-1;
|
||||||
count = bitmap_weight(bits, 2048 * BITS_PER_BYTE);
|
count = bitmap_weight(bits, 2048 * BITS_PER_BYTE);
|
||||||
hpfs_brelse4(&qbh);
|
hpfs_brelse4(&qbh);
|
||||||
return count;
|
return count;
|
||||||
|
@ -144,30 +144,45 @@ static unsigned count_bitmaps(struct super_block *s)
|
||||||
hpfs_prefetch_bitmap(s, n);
|
hpfs_prefetch_bitmap(s, n);
|
||||||
}
|
}
|
||||||
for (n = 0; n < n_bands; n++) {
|
for (n = 0; n < n_bands; n++) {
|
||||||
|
unsigned c;
|
||||||
hpfs_prefetch_bitmap(s, n + COUNT_RD_AHEAD);
|
hpfs_prefetch_bitmap(s, n + COUNT_RD_AHEAD);
|
||||||
count += hpfs_count_one_bitmap(s, le32_to_cpu(hpfs_sb(s)->sb_bmp_dir[n]));
|
c = hpfs_count_one_bitmap(s, le32_to_cpu(hpfs_sb(s)->sb_bmp_dir[n]));
|
||||||
|
if (c != (unsigned)-1)
|
||||||
|
count += c;
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned hpfs_get_free_dnodes(struct super_block *s)
|
||||||
|
{
|
||||||
|
struct hpfs_sb_info *sbi = hpfs_sb(s);
|
||||||
|
if (sbi->sb_n_free_dnodes == (unsigned)-1) {
|
||||||
|
unsigned c = hpfs_count_one_bitmap(s, sbi->sb_dmap);
|
||||||
|
if (c == (unsigned)-1)
|
||||||
|
return 0;
|
||||||
|
sbi->sb_n_free_dnodes = c;
|
||||||
|
}
|
||||||
|
return sbi->sb_n_free_dnodes;
|
||||||
|
}
|
||||||
|
|
||||||
static int hpfs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
static int hpfs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
||||||
{
|
{
|
||||||
struct super_block *s = dentry->d_sb;
|
struct super_block *s = dentry->d_sb;
|
||||||
struct hpfs_sb_info *sbi = hpfs_sb(s);
|
struct hpfs_sb_info *sbi = hpfs_sb(s);
|
||||||
u64 id = huge_encode_dev(s->s_bdev->bd_dev);
|
u64 id = huge_encode_dev(s->s_bdev->bd_dev);
|
||||||
|
|
||||||
hpfs_lock(s);
|
hpfs_lock(s);
|
||||||
|
|
||||||
/*if (sbi->sb_n_free == -1) {*/
|
if (sbi->sb_n_free == (unsigned)-1)
|
||||||
sbi->sb_n_free = count_bitmaps(s);
|
sbi->sb_n_free = count_bitmaps(s);
|
||||||
sbi->sb_n_free_dnodes = hpfs_count_one_bitmap(s, sbi->sb_dmap);
|
|
||||||
/*}*/
|
|
||||||
buf->f_type = s->s_magic;
|
buf->f_type = s->s_magic;
|
||||||
buf->f_bsize = 512;
|
buf->f_bsize = 512;
|
||||||
buf->f_blocks = sbi->sb_fs_size;
|
buf->f_blocks = sbi->sb_fs_size;
|
||||||
buf->f_bfree = sbi->sb_n_free;
|
buf->f_bfree = sbi->sb_n_free;
|
||||||
buf->f_bavail = sbi->sb_n_free;
|
buf->f_bavail = sbi->sb_n_free;
|
||||||
buf->f_files = sbi->sb_dirband_size / 4;
|
buf->f_files = sbi->sb_dirband_size / 4;
|
||||||
buf->f_ffree = sbi->sb_n_free_dnodes;
|
buf->f_ffree = hpfs_get_free_dnodes(s);
|
||||||
buf->f_fsid.val[0] = (u32)id;
|
buf->f_fsid.val[0] = (u32)id;
|
||||||
buf->f_fsid.val[1] = (u32)(id >> 32);
|
buf->f_fsid.val[1] = (u32)(id >> 32);
|
||||||
buf->f_namelen = 254;
|
buf->f_namelen = 254;
|
||||||
|
|
Loading…
Reference in a new issue