#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
        }
        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;
        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;
 }
 
                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);
                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);
                bmp[ssec >> 5] |= cpu_to_le32(1 << (ssec & 0x1f));
                hpfs_mark_4buffers_dirty(&qbh);
                hpfs_brelse4(&qbh);
+               hpfs_claim_dirband_free(s, dno);
        }
 }
 
                         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 {
 
        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;
 
        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;
                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;