]> git.proxmox.com Git - mirror_ubuntu-kernels.git/blobdiff - fs/ntfs3/bitmap.c
Merge tag 'nfsd-6.2-6' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux
[mirror_ubuntu-kernels.git] / fs / ntfs3 / bitmap.c
index e92bbd754365ed3bc64559cfed0865ef36eec648..723fb64e653160a5ce42194429fd7d71c4acbe1b 100644 (file)
@@ -59,14 +59,14 @@ void ntfs3_exit_bitmap(void)
  *
  * Return: -1 if not found.
  */
-static size_t wnd_scan(const ulong *buf, size_t wbit, u32 wpos, u32 wend,
+static size_t wnd_scan(const void *buf, size_t wbit, u32 wpos, u32 wend,
                       size_t to_alloc, size_t *prev_tail, size_t *b_pos,
                       size_t *b_len)
 {
        while (wpos < wend) {
                size_t free_len;
                u32 free_bits, end;
-               u32 used = find_next_zero_bit(buf, wend, wpos);
+               u32 used = find_next_zero_bit_le(buf, wend, wpos);
 
                if (used >= wend) {
                        if (*b_len < *prev_tail) {
@@ -92,7 +92,7 @@ static size_t wnd_scan(const ulong *buf, size_t wbit, u32 wpos, u32 wend,
                 * Now we have a fragment [wpos, wend) staring with 0.
                 */
                end = wpos + to_alloc - *prev_tail;
-               free_bits = find_next_bit(buf, min(end, wend), wpos);
+               free_bits = find_next_bit_le(buf, min(end, wend), wpos);
 
                free_len = *prev_tail + free_bits - wpos;
 
@@ -504,7 +504,6 @@ static int wnd_rescan(struct wnd_bitmap *wnd)
        u8 cluster_bits = sbi->cluster_bits;
        u32 wbits = 8 * sb->s_blocksize;
        u32 used, frb;
-       const ulong *buf;
        size_t wpos, wbit, iw, vbo;
        struct buffer_head *bh = NULL;
        CLST lcn, clen;
@@ -558,9 +557,7 @@ static int wnd_rescan(struct wnd_bitmap *wnd)
                        goto out;
                }
 
-               buf = (ulong *)bh->b_data;
-
-               used = bitmap_weight(buf, wbits);
+               used = ntfs_bitmap_weight_le(bh->b_data, wbits);
                if (used < wbits) {
                        frb = wbits - used;
                        wnd->free_bits[iw] = frb;
@@ -574,7 +571,7 @@ static int wnd_rescan(struct wnd_bitmap *wnd)
                        wbits = wnd->nbits - wbit;
 
                do {
-                       used = find_next_zero_bit(buf, wbits, wpos);
+                       used = find_next_zero_bit_le(bh->b_data, wbits, wpos);
 
                        if (used > wpos && prev_tail) {
                                wnd_add_free_ext(wnd, wbit + wpos - prev_tail,
@@ -590,7 +587,7 @@ static int wnd_rescan(struct wnd_bitmap *wnd)
                                break;
                        }
 
-                       frb = find_next_bit(buf, wbits, wpos);
+                       frb = find_next_bit_le(bh->b_data, wbits, wpos);
                        if (frb >= wbits) {
                                /* Keep last free block. */
                                prev_tail += frb - wpos;
@@ -661,7 +658,7 @@ int wnd_init(struct wnd_bitmap *wnd, struct super_block *sb, size_t nbits)
        if (!wnd->bits_last)
                wnd->bits_last = wbits;
 
-       wnd->free_bits = kcalloc(wnd->nwnd, sizeof(u16), GFP_NOFS);
+       wnd->free_bits = kcalloc(wnd->nwnd, sizeof(u16), GFP_NOFS | __GFP_NOWARN);
        if (!wnd->free_bits)
                return -ENOMEM;
 
@@ -718,7 +715,6 @@ int wnd_set_free(struct wnd_bitmap *wnd, size_t bit, size_t bits)
 
        while (iw < wnd->nwnd && bits) {
                u32 tail, op;
-               ulong *buf;
 
                if (iw + 1 == wnd->nwnd)
                        wbits = wnd->bits_last;
@@ -732,11 +728,9 @@ int wnd_set_free(struct wnd_bitmap *wnd, size_t bit, size_t bits)
                        break;
                }
 
-               buf = (ulong *)bh->b_data;
-
                lock_buffer(bh);
 
-               __bitmap_clear(buf, wbit, op);
+               ntfs_bitmap_clear_le(bh->b_data, wbit, op);
 
                wnd->free_bits[iw] += op;
 
@@ -771,7 +765,6 @@ int wnd_set_used(struct wnd_bitmap *wnd, size_t bit, size_t bits)
 
        while (iw < wnd->nwnd && bits) {
                u32 tail, op;
-               ulong *buf;
 
                if (unlikely(iw + 1 == wnd->nwnd))
                        wbits = wnd->bits_last;
@@ -784,11 +777,10 @@ int wnd_set_used(struct wnd_bitmap *wnd, size_t bit, size_t bits)
                        err = PTR_ERR(bh);
                        break;
                }
-               buf = (ulong *)bh->b_data;
 
                lock_buffer(bh);
 
-               __bitmap_set(buf, wbit, op);
+               ntfs_bitmap_set_le(bh->b_data, wbit, op);
                wnd->free_bits[iw] -= op;
 
                set_buffer_uptodate(bh);
@@ -808,6 +800,44 @@ int wnd_set_used(struct wnd_bitmap *wnd, size_t bit, size_t bits)
        return err;
 }
 
+/*
+ * wnd_set_used_safe - Mark the bits range from bit to bit + bits as used.
+ *
+ * Unlikely wnd_set_used/wnd_set_free this function is not full trusted.
+ * It scans every bit in bitmap and marks free bit as used.
+ * @done - how many bits were marked as used.
+ *
+ * NOTE: normally *done should be 0.
+ */
+int wnd_set_used_safe(struct wnd_bitmap *wnd, size_t bit, size_t bits,
+                     size_t *done)
+{
+       size_t i, from = 0, len = 0;
+       int err = 0;
+
+       *done = 0;
+       for (i = 0; i < bits; i++) {
+               if (wnd_is_free(wnd, bit + i, 1)) {
+                       if (!len)
+                               from = bit + i;
+                       len += 1;
+               } else if (len) {
+                       err = wnd_set_used(wnd, from, len);
+                       *done += len;
+                       len = 0;
+                       if (err)
+                               break;
+               }
+       }
+
+       if (len) {
+               /* last fragment. */
+               err = wnd_set_used(wnd, from, len);
+               *done += len;
+       }
+       return err;
+}
+
 /*
  * wnd_is_free_hlp
  *
@@ -836,7 +866,7 @@ static bool wnd_is_free_hlp(struct wnd_bitmap *wnd, size_t bit, size_t bits)
                        if (IS_ERR(bh))
                                return false;
 
-                       ret = are_bits_clear((ulong *)bh->b_data, wbit, op);
+                       ret = are_bits_clear(bh->b_data, wbit, op);
 
                        put_bh(bh);
                        if (!ret)
@@ -928,7 +958,7 @@ use_wnd:
                        if (IS_ERR(bh))
                                goto out;
 
-                       ret = are_bits_set((ulong *)bh->b_data, wbit, op);
+                       ret = are_bits_set(bh->b_data, wbit, op);
                        put_bh(bh);
                        if (!ret)
                                goto out;
@@ -959,7 +989,6 @@ size_t wnd_find(struct wnd_bitmap *wnd, size_t to_alloc, size_t hint,
        size_t fnd, max_alloc, b_len, b_pos;
        size_t iw, prev_tail, nwnd, wbit, ebit, zbit, zend;
        size_t to_alloc0 = to_alloc;
-       const ulong *buf;
        const struct e_node *e;
        const struct rb_node *pr, *cr;
        u8 log2_bits;
@@ -1185,14 +1214,13 @@ Again:
                                        continue;
                                }
 
-                               buf = (ulong *)bh->b_data;
-
                                /* Scan range [wbit, zbit). */
                                if (wpos < wzbit) {
                                        /* Scan range [wpos, zbit). */
-                                       fnd = wnd_scan(buf, wbit, wpos, wzbit,
-                                                      to_alloc, &prev_tail,
-                                                      &b_pos, &b_len);
+                                       fnd = wnd_scan(bh->b_data, wbit, wpos,
+                                                      wzbit, to_alloc,
+                                                      &prev_tail, &b_pos,
+                                                      &b_len);
                                        if (fnd != MINUS_ONE_T) {
                                                put_bh(bh);
                                                goto found;
@@ -1203,7 +1231,7 @@ Again:
 
                                /* Scan range [zend, ebit). */
                                if (wzend < wbits) {
-                                       fnd = wnd_scan(buf, wbit,
+                                       fnd = wnd_scan(bh->b_data, wbit,
                                                       max(wzend, wpos), wbits,
                                                       to_alloc, &prev_tail,
                                                       &b_pos, &b_len);
@@ -1242,11 +1270,9 @@ Again:
                        continue;
                }
 
-               buf = (ulong *)bh->b_data;
-
                /* Scan range [wpos, eBits). */
-               fnd = wnd_scan(buf, wbit, wpos, wbits, to_alloc, &prev_tail,
-                              &b_pos, &b_len);
+               fnd = wnd_scan(bh->b_data, wbit, wpos, wbits, to_alloc,
+                              &prev_tail, &b_pos, &b_len);
                put_bh(bh);
                if (fnd != MINUS_ONE_T)
                        goto found;
@@ -1324,7 +1350,7 @@ int wnd_extend(struct wnd_bitmap *wnd, size_t new_bits)
                new_last = wbits;
 
        if (new_wnd != wnd->nwnd) {
-               new_free = kmalloc(new_wnd * sizeof(u16), GFP_NOFS);
+               new_free = kmalloc_array(new_wnd, sizeof(u16), GFP_NOFS);
                if (!new_free)
                        return -ENOMEM;
 
@@ -1344,7 +1370,6 @@ int wnd_extend(struct wnd_bitmap *wnd, size_t new_bits)
                size_t frb;
                u64 vbo, lbo, bytes;
                struct buffer_head *bh;
-               ulong *buf;
 
                if (iw + 1 == new_wnd)
                        wbits = new_last;
@@ -1361,10 +1386,9 @@ int wnd_extend(struct wnd_bitmap *wnd, size_t new_bits)
                        return -EIO;
 
                lock_buffer(bh);
-               buf = (ulong *)bh->b_data;
 
-               __bitmap_clear(buf, b0, blocksize * 8 - b0);
-               frb = wbits - bitmap_weight(buf, wbits);
+               ntfs_bitmap_clear_le(bh->b_data, b0, blocksize * 8 - b0);
+               frb = wbits - ntfs_bitmap_weight_le(bh->b_data, wbits);
                wnd->total_zeroes += frb - wnd->free_bits[iw];
                wnd->free_bits[iw] = frb;
 
@@ -1411,7 +1435,6 @@ int ntfs_trim_fs(struct ntfs_sb_info *sbi, struct fstrim_range *range)
        CLST lcn_from = bytes_to_cluster(sbi, range->start);
        size_t iw = lcn_from >> (sb->s_blocksize_bits + 3);
        u32 wbit = lcn_from & (wbits - 1);
-       const ulong *buf;
        CLST lcn_to;
 
        if (!minlen)
@@ -1424,7 +1447,7 @@ int ntfs_trim_fs(struct ntfs_sb_info *sbi, struct fstrim_range *range)
 
        down_read_nested(&wnd->rw_lock, BITMAP_MUTEX_CLUSTERS);
 
-       for (; iw < wnd->nbits; iw++, wbit = 0) {
+       for (; iw < wnd->nwnd; iw++, wbit = 0) {
                CLST lcn_wnd = iw * wbits;
                struct buffer_head *bh;
 
@@ -1446,10 +1469,8 @@ int ntfs_trim_fs(struct ntfs_sb_info *sbi, struct fstrim_range *range)
                        break;
                }
 
-               buf = (ulong *)bh->b_data;
-
                for (; wbit < wbits; wbit++) {
-                       if (!test_bit(wbit, buf)) {
+                       if (!test_bit_le(wbit, bh->b_data)) {
                                if (!len)
                                        lcn = lcn_wnd + wbit;
                                len += 1;
@@ -1481,3 +1502,70 @@ out:
 
        return err;
 }
+
+#if BITS_PER_LONG == 64
+typedef __le64 bitmap_ulong;
+#define cpu_to_ul(x) cpu_to_le64(x)
+#define ul_to_cpu(x) le64_to_cpu(x)
+#else
+typedef __le32 bitmap_ulong;
+#define cpu_to_ul(x) cpu_to_le32(x)
+#define ul_to_cpu(x) le32_to_cpu(x)
+#endif
+
+void ntfs_bitmap_set_le(void *map, unsigned int start, int len)
+{
+       bitmap_ulong *p = (bitmap_ulong *)map + BIT_WORD(start);
+       const unsigned int size = start + len;
+       int bits_to_set = BITS_PER_LONG - (start % BITS_PER_LONG);
+       bitmap_ulong mask_to_set = cpu_to_ul(BITMAP_FIRST_WORD_MASK(start));
+
+       while (len - bits_to_set >= 0) {
+               *p |= mask_to_set;
+               len -= bits_to_set;
+               bits_to_set = BITS_PER_LONG;
+               mask_to_set = cpu_to_ul(~0UL);
+               p++;
+       }
+       if (len) {
+               mask_to_set &= cpu_to_ul(BITMAP_LAST_WORD_MASK(size));
+               *p |= mask_to_set;
+       }
+}
+
+void ntfs_bitmap_clear_le(void *map, unsigned int start, int len)
+{
+       bitmap_ulong *p = (bitmap_ulong *)map + BIT_WORD(start);
+       const unsigned int size = start + len;
+       int bits_to_clear = BITS_PER_LONG - (start % BITS_PER_LONG);
+       bitmap_ulong mask_to_clear = cpu_to_ul(BITMAP_FIRST_WORD_MASK(start));
+
+       while (len - bits_to_clear >= 0) {
+               *p &= ~mask_to_clear;
+               len -= bits_to_clear;
+               bits_to_clear = BITS_PER_LONG;
+               mask_to_clear = cpu_to_ul(~0UL);
+               p++;
+       }
+       if (len) {
+               mask_to_clear &= cpu_to_ul(BITMAP_LAST_WORD_MASK(size));
+               *p &= ~mask_to_clear;
+       }
+}
+
+unsigned int ntfs_bitmap_weight_le(const void *bitmap, int bits)
+{
+       const ulong *bmp = bitmap;
+       unsigned int k, lim = bits / BITS_PER_LONG;
+       unsigned int w = 0;
+
+       for (k = 0; k < lim; k++)
+               w += hweight_long(bmp[k]);
+
+       if (bits % BITS_PER_LONG) {
+               w += hweight_long(ul_to_cpu(((bitmap_ulong *)bitmap)[k]) &
+                                 BITMAP_LAST_WORD_MASK(bits));
+       }
+
+       return w;
+}