summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/hpfs/alloc.c66
-rw-r--r--fs/hpfs/buffer.c96
-rw-r--r--fs/hpfs/hpfs_fn.h2
-rw-r--r--fs/hpfs/super.c29
4 files changed, 137 insertions, 56 deletions
diff --git a/fs/hpfs/alloc.c b/fs/hpfs/alloc.c
index cdb84a838068..58b5106186d0 100644
--- a/fs/hpfs/alloc.c
+++ b/fs/hpfs/alloc.c
@@ -8,6 +8,58 @@
#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
* 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;
ret:
+ if (sec) {
+ i = 0;
+ do
+ hpfs_claim_alloc(s, sec + i);
+ while (unlikely(++i < n));
+ }
if (sec && f_p) {
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);
sec = 0;
break;
@@ -228,6 +286,7 @@ static secno alloc_in_dirband(struct super_block *s, secno near)
nr >>= 2;
sec = alloc_in_bmp(s, (~0x3fff) | nr, 1, 0);
if (!sec) return 0;
+ hpfs_claim_dirband_alloc(s, sec);
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)));
hpfs_mark_4buffers_dirty(&qbh);
hpfs_brelse4(&qbh);
+ hpfs_claim_alloc(s, sec);
return 1;
}
hpfs_brelse4(&qbh);
@@ -275,6 +335,7 @@ void hpfs_free_sectors(struct super_block *s, secno sec, unsigned n)
return;
}
bmp[(sec & 0x3fff) >> 5] |= cpu_to_le32(1 << (sec & 0x1f));
+ hpfs_claim_free(s, sec);
if (!--n) {
hpfs_mark_4buffers_dirty(&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));
hpfs_mark_4buffers_dirty(&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)
{
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 = hpfs_alloc_sector(s, near, 4, 0))) return NULL;
} else {
diff --git a/fs/hpfs/buffer.c b/fs/hpfs/buffer.c
index 4d0a1afa058c..139ef1684d07 100644
--- a/fs/hpfs/buffer.c
+++ b/fs/hpfs/buffer.c
@@ -86,7 +86,6 @@ void *hpfs_get_sector(struct super_block *s, unsigned secno, struct buffer_head
void *hpfs_map_4sectors(struct super_block *s, unsigned secno, struct quad_buffer_head *qbh,
int ahead)
{
- struct buffer_head *bh;
char *data;
hpfs_lock_assert(s);
@@ -100,34 +99,32 @@ void *hpfs_map_4sectors(struct super_block *s, unsigned secno, struct quad_buffe
hpfs_prefetch_sectors(s, secno, 4 + ahead);
+ if (!(qbh->bh[0] = sb_bread(s, secno + 0))) goto bail0;
+ if (!(qbh->bh[1] = sb_bread(s, secno + 1))) goto bail1;
+ if (!(qbh->bh[2] = sb_bread(s, secno + 2))) goto bail2;
+ if (!(qbh->bh[3] = sb_bread(s, secno + 3))) goto bail3;
+
+ if (likely(qbh->bh[1]->b_data == qbh->bh[0]->b_data + 1 * 512) &&
+ likely(qbh->bh[2]->b_data == qbh->bh[0]->b_data + 2 * 512) &&
+ likely(qbh->bh[3]->b_data == qbh->bh[0]->b_data + 3 * 512)) {
+ return qbh->data = qbh->bh[0]->b_data;
+ }
+
qbh->data = data = kmalloc(2048, GFP_NOFS);
if (!data) {
printk("HPFS: hpfs_map_4sectors: out of memory\n");
- goto bail;
+ goto bail4;
}
- qbh->bh[0] = bh = sb_bread(s, secno);
- if (!bh)
- goto bail0;
- memcpy(data, bh->b_data, 512);
-
- qbh->bh[1] = bh = sb_bread(s, secno + 1);
- if (!bh)
- goto bail1;
- memcpy(data + 512, bh->b_data, 512);
-
- qbh->bh[2] = bh = sb_bread(s, secno + 2);
- if (!bh)
- goto bail2;
- memcpy(data + 2 * 512, bh->b_data, 512);
-
- qbh->bh[3] = bh = sb_bread(s, secno + 3);
- if (!bh)
- goto bail3;
- memcpy(data + 3 * 512, bh->b_data, 512);
+ memcpy(data + 0 * 512, qbh->bh[0]->b_data, 512);
+ memcpy(data + 1 * 512, qbh->bh[1]->b_data, 512);
+ memcpy(data + 2 * 512, qbh->bh[2]->b_data, 512);
+ memcpy(data + 3 * 512, qbh->bh[3]->b_data, 512);
return data;
+ bail4:
+ brelse(qbh->bh[3]);
bail3:
brelse(qbh->bh[2]);
bail2:
@@ -135,9 +132,6 @@ void *hpfs_map_4sectors(struct super_block *s, unsigned secno, struct quad_buffe
bail1:
brelse(qbh->bh[0]);
bail0:
- kfree(data);
- printk("HPFS: hpfs_map_4sectors: read error\n");
- bail:
return NULL;
}
@@ -155,44 +149,54 @@ void *hpfs_get_4sectors(struct super_block *s, unsigned secno,
return NULL;
}
- /*return hpfs_map_4sectors(s, secno, qbh, 0);*/
+ if (!hpfs_get_sector(s, secno + 0, &qbh->bh[0])) goto bail0;
+ if (!hpfs_get_sector(s, secno + 1, &qbh->bh[1])) goto bail1;
+ if (!hpfs_get_sector(s, secno + 2, &qbh->bh[2])) goto bail2;
+ if (!hpfs_get_sector(s, secno + 3, &qbh->bh[3])) goto bail3;
+
+ if (likely(qbh->bh[1]->b_data == qbh->bh[0]->b_data + 1 * 512) &&
+ likely(qbh->bh[2]->b_data == qbh->bh[0]->b_data + 2 * 512) &&
+ likely(qbh->bh[3]->b_data == qbh->bh[0]->b_data + 3 * 512)) {
+ return qbh->data = qbh->bh[0]->b_data;
+ }
+
if (!(qbh->data = kmalloc(2048, GFP_NOFS))) {
printk("HPFS: hpfs_get_4sectors: out of memory\n");
- return NULL;
+ goto bail4;
}
- if (!(hpfs_get_sector(s, secno, &qbh->bh[0]))) goto bail0;
- if (!(hpfs_get_sector(s, secno + 1, &qbh->bh[1]))) goto bail1;
- if (!(hpfs_get_sector(s, secno + 2, &qbh->bh[2]))) goto bail2;
- if (!(hpfs_get_sector(s, secno + 3, &qbh->bh[3]))) goto bail3;
- memcpy(qbh->data, qbh->bh[0]->b_data, 512);
- memcpy(qbh->data + 512, qbh->bh[1]->b_data, 512);
- memcpy(qbh->data + 2*512, qbh->bh[2]->b_data, 512);
- memcpy(qbh->data + 3*512, qbh->bh[3]->b_data, 512);
return qbh->data;
- bail3: brelse(qbh->bh[2]);
- bail2: brelse(qbh->bh[1]);
- bail1: brelse(qbh->bh[0]);
- bail0:
+bail4:
+ brelse(qbh->bh[3]);
+bail3:
+ brelse(qbh->bh[2]);
+bail2:
+ brelse(qbh->bh[1]);
+bail1:
+ brelse(qbh->bh[0]);
+bail0:
return NULL;
}
void hpfs_brelse4(struct quad_buffer_head *qbh)
{
- brelse(qbh->bh[3]);
- brelse(qbh->bh[2]);
- brelse(qbh->bh[1]);
+ if (unlikely(qbh->data != qbh->bh[0]->b_data))
+ kfree(qbh->data);
brelse(qbh->bh[0]);
- kfree(qbh->data);
+ brelse(qbh->bh[1]);
+ brelse(qbh->bh[2]);
+ brelse(qbh->bh[3]);
}
void hpfs_mark_4buffers_dirty(struct quad_buffer_head *qbh)
{
- memcpy(qbh->bh[0]->b_data, qbh->data, 512);
- memcpy(qbh->bh[1]->b_data, qbh->data + 512, 512);
- memcpy(qbh->bh[2]->b_data, qbh->data + 2 * 512, 512);
- memcpy(qbh->bh[3]->b_data, qbh->data + 3 * 512, 512);
+ if (unlikely(qbh->data != qbh->bh[0]->b_data)) {
+ memcpy(qbh->bh[0]->b_data, qbh->data + 0 * 512, 512);
+ memcpy(qbh->bh[1]->b_data, qbh->data + 1 * 512, 512);
+ memcpy(qbh->bh[2]->b_data, qbh->data + 2 * 512, 512);
+ memcpy(qbh->bh[3]->b_data, qbh->data + 3 * 512, 512);
+ }
mark_buffer_dirty(qbh->bh[0]);
mark_buffer_dirty(qbh->bh[1]);
mark_buffer_dirty(qbh->bh[2]);
diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h
index 6797bf80f6e2..3ba49c080e42 100644
--- a/fs/hpfs/hpfs_fn.h
+++ b/fs/hpfs/hpfs_fn.h
@@ -312,7 +312,7 @@ static inline struct hpfs_sb_info *hpfs_sb(struct super_block *sb)
__printf(2, 3)
void hpfs_error(struct super_block *, const 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)
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c
index b8d01ef6f531..4534ff688b76 100644
--- a/fs/hpfs/super.c
+++ b/fs/hpfs/super.c
@@ -121,7 +121,7 @@ static void hpfs_put_super(struct super_block *s)
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;
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);
if (!bits)
- return 0;
+ return (unsigned)-1;
count = bitmap_weight(bits, 2048 * BITS_PER_BYTE);
hpfs_brelse4(&qbh);
return count;
@@ -144,30 +144,45 @@ static unsigned count_bitmaps(struct super_block *s)
hpfs_prefetch_bitmap(s, n);
}
for (n = 0; n < n_bands; n++) {
+ unsigned c;
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;
}
+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)
{
struct super_block *s = dentry->d_sb;
struct hpfs_sb_info *sbi = hpfs_sb(s);
u64 id = huge_encode_dev(s->s_bdev->bd_dev);
+
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_dnodes = hpfs_count_one_bitmap(s, sbi->sb_dmap);
- /*}*/
+
buf->f_type = s->s_magic;
buf->f_bsize = 512;
buf->f_blocks = sbi->sb_fs_size;
buf->f_bfree = sbi->sb_n_free;
buf->f_bavail = sbi->sb_n_free;
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[1] = (u32)(id >> 32);
buf->f_namelen = 254;