blob: f6cb8563d0323324bd3d4a69decd0d851cb6a30a [file] [log] [blame]
/*
* Utility functions.
*
* Copyright (c) 2009-2014 Daniel Phillips
* Copyright (c) 2009-2014 OGAWA Hirofumi
*/
#ifdef __KERNEL__
#include "tux3.h"
#include "kcompat.h"
int vecio(int rw, struct block_device *dev, loff_t offset, unsigned vecs, struct bio_vec *vec,
bio_end_io_t endio, void *info)
{
BUG_ON(vecs > bio_get_nr_vecs(dev));
struct bio *bio = bio_alloc(GFP_NOIO, vecs);
if (!bio)
return -ENOMEM;
bio->bi_bdev = dev;
bio_bi_sector(bio) = offset >> 9;
bio->bi_end_io = endio;
bio->bi_private = info;
bio->bi_vcnt = vecs;
memcpy(bio->bi_io_vec, vec, sizeof(*vec) * vecs);
while (vecs--)
bio_bi_size(bio) += bio->bi_io_vec[vecs].bv_len;
submit_bio(rw, bio);
return 0;
}
struct biosync { struct completion done; int err; };
static void biosync_endio(struct bio *bio, int err)
{
struct biosync *sync = bio->bi_private;
bio_put(bio);
sync->err = err;
complete(&sync->done);
}
int syncio(int rw, struct block_device *dev, loff_t offset, unsigned vecs, struct bio_vec *vec)
{
struct biosync sync = { .done = COMPLETION_INITIALIZER_ONSTACK(sync.done) };
if (!(sync.err = vecio(rw, dev, offset, vecs, vec, biosync_endio, &sync)))
wait_for_completion(&sync.done);
return sync.err;
}
int devio(int rw, struct block_device *dev, loff_t offset, void *data, unsigned len)
{
return syncio(rw, dev, offset, 1, &(struct bio_vec){
.bv_page = virt_to_page(data),
.bv_offset = offset_in_page(data),
.bv_len = len });
}
int blockio(int rw, struct sb *sb, struct buffer_head *buffer, block_t block)
{
struct bio_vec vec = {
.bv_page = buffer->b_page,
.bv_offset = bh_offset(buffer),
.bv_len = sb->blocksize,
};
return syncio(rw, sb_dev(sb), block << sb->blockbits, 1, &vec);
}
/*
* bufvec based I/O. This takes the bufvec has contiguous range, and
* will submit the count of buffers to block (physical address).
*
* If there was I/O error, it would be handled in ->bi_end_bio()
* completion.
*/
int blockio_vec(int rw, struct bufvec *bufvec, block_t block, unsigned count)
{
return bufvec_io(rw, bufvec, block, count);
}
void hexdump(void *data, unsigned size)
{
print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 16, 1, data, size, 1);
}
/*
* Message helpers
*/
void __tux3_msg(struct sb *sb, const char *level, const char *prefix,
const char *fmt, ...)
{
struct va_format vaf;
va_list args;
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
printk("%sTUX3-fs%s (%s): %pV\n", level, prefix,
vfs_sb(sb)->s_id, &vaf);
va_end(args);
}
void __tux3_fs_error(struct sb *sb, const char *func, unsigned int line,
const char *fmt, ...)
{
struct va_format vaf;
va_list args;
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
printk(KERN_ERR "TUX3-fs error (%s): %s:%d: %pV\n",
vfs_sb(sb)->s_id, func, line, &vaf);
va_end(args);
BUG(); /* FIXME: maybe panic() or MS_RDONLY */
}
void __tux3_dbg(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vprintk(fmt, args);
va_end(args);
}
#endif /* !__KERNEL__ */
/* Bitmap operations... try to use linux/lib/bitmap.c */
void set_bits(u8 *bitmap, unsigned start, unsigned count)
{
unsigned limit = start + count;
unsigned lmask = (-1 << (start & 7)) & 0xff; // little endian!!!
unsigned rmask = ~(-1 << (limit & 7)) & 0xff; // little endian!!!
unsigned loff = start >> 3, roff = limit >> 3;
if (loff == roff) {
bitmap[loff] |= lmask & rmask;
return;
}
bitmap[loff] |= lmask;
memset(bitmap + loff + 1, -1, roff - loff - 1);
if (rmask)
bitmap[roff] |= rmask;
}
void clear_bits(u8 *bitmap, unsigned start, unsigned count)
{
unsigned limit = start + count;
unsigned lmask = (-1 << (start & 7)) & 0xff; // little endian!!!
unsigned rmask = ~(-1 << (limit & 7)) & 0xff; // little endian!!!
unsigned loff = start >> 3, roff = limit >> 3;
if (loff == roff) {
bitmap[loff] &= ~lmask | ~rmask;
return;
}
bitmap[loff] &= ~lmask;
memset(bitmap + loff + 1, 0, roff - loff - 1);
if (rmask)
bitmap[roff] &= ~rmask;
}
int all_set(u8 *bitmap, unsigned start, unsigned count)
{
#if 1
/* Bitmap must be array of "unsigned long" */
unsigned limit = start + count;
/* Find zero bit in range. If not found, all are non-zero. */
return find_next_zero_bit_le(bitmap, limit, start) == limit;
#else
unsigned limit = start + count;
unsigned lmask = (-1 << (start & 7)) & 0xff; /* little endian!!! */
unsigned rmask = ~(-1 << (limit & 7)) & 0xff; /* little endian!!! */
unsigned loff = start >> 3, roff = limit >> 3;
if (loff == roff) {
unsigned mask = lmask & rmask;
return (bitmap[loff] & mask) == mask;
}
for (unsigned i = loff + 1; i < roff; i++)
if (bitmap[i] != 0xff)
return 0;
return (bitmap[loff] & lmask) == lmask &&
(!rmask || (bitmap[roff] & rmask) == rmask);
#endif
}
int all_clear(u8 *bitmap, unsigned start, unsigned count)
{
#if 1
/* Bitmap must be array of "unsigned long" */
unsigned limit = start + count;
/* Find non-zero bit in range. If not found, all are zero. */
return find_next_bit_le(bitmap, limit, start) == limit;
#else
unsigned limit = start + count;
unsigned lmask = (-1 << (start & 7)) & 0xff; /* little endian!!! */
unsigned rmask = ~(-1 << (limit & 7)) & 0xff; /* little endian!!! */
unsigned loff = start >> 3, roff = limit >> 3;
if (loff == roff) {
unsigned mask = lmask & rmask;
return !(bitmap[loff] & mask);
}
for (unsigned i = loff + 1; i < roff; i++)
if (bitmap[i])
return 0;
return !(bitmap[loff] & lmask) &&
(!rmask || !(bitmap[roff] & rmask));
#endif
}
int bytebits(u8 c)
{
unsigned count = 0;
for (; c; c >>= 1)
count += c & 1;
return count;
}