}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
+#define B_REQ_WRITE REQ_WRITE
#define B_REQ_SYNC REQ_SYNC
#define B_REQ_UNPLUG REQ_UNPLUG
#define B_REQ_NOIDLE REQ_NOIDLE
#define B_REQ_FAILFAST_DEV REQ_FAILFAST_DEV
#define B_REQ_FAILFAST_TRANSPORT REQ_FAILFAST_TRANSPORT
#define B_REQ_FAILFAST_DRIVER REQ_FAILFAST_DRIVER
+#define B_REQ_DISCARD REQ_DISCARD
+#define B_REQ_FLUSH REQ_FLUSH
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
+#define B_REQ_WRITE (1 << BIO_RW)
#define B_REQ_SYNC (1 << BIO_RW_SYNC)
#define B_REQ_UNPLUG 0
#define B_REQ_NOIDLE 0
#define B_REQ_FAILFAST_DEV (1 << BIO_RW_FAILFAST)
#define B_REQ_FAILFAST_TRANSPORT (1 << BIO_RW_FAILFAST)
#define B_REQ_FAILFAST_DRIVER (1 << BIO_RW_FAILFAST)
+#define B_REQ_DISCARD 0
+#define B_REQ_FLUSH 0
#else
#error The kernel is too old
#endif
unsigned int data_transfer : 1;
unsigned int todevice : 1;
unsigned int map_zero : 1;
+ unsigned long rw_flags;
};
static const struct uc_map uc_map[B_TYPE_NR] = {
.data_transfer = 1,
.todevice = 1,
.map_zero = 0,
+ .rw_flags = B_REQ_WRITE,
},
{
.type = B_TYPE_DISCARD,
.data_transfer = 0,
.todevice = 0,
.map_zero = 0,
+ .rw_flags = B_REQ_DISCARD | B_REQ_WRITE,
},
{
.type = B_TYPE_READVOID,
.data_transfer = 1,
.todevice = 1,
.map_zero = 1,
+ .rw_flags = B_REQ_WRITE,
+ },
+ {
+ .type = B_TYPE_READBARRIER,
+ .data_transfer = 1,
+ .todevice = 0,
+ .map_zero = 0,
+ .rw_flags = B_REQ_HARDBARRIER,
+ },
+ {
+ .type = B_TYPE_WRITEBARRIER,
+ .data_transfer = 1,
+ .todevice = 1,
+ .map_zero = 0,
+ .rw_flags = B_REQ_HARDBARRIER | B_REQ_FLUSH | B_REQ_WRITE,
}
};
}
#endif
+#define len_to_pages(len) ((len + PAGE_SIZE - 1) / PAGE_SIZE)
+
static int zero_map_bio(struct request_queue *q, struct bio *bio,
const struct uc_map *ucm, unsigned int len)
{
unsigned int i, nr_pages, this_len, ret, err;
struct page *page;
- nr_pages = len / PAGE_SIZE;
+ nr_pages = len_to_pages(len);
for (i = 0; i < nr_pages; i++) {
if (ucm->todevice)
page = ZERO_PAGE(0);
if (this_len > len)
this_len = len;
- ret = bio_add_pc_page(q, bio, page, len, 0);
- if (ret < len) {
+ ret = bio_add_pc_page(q, bio, page, this_len, 0);
+ if (ret < this_len) {
err = -E2BIG;
goto oom;
}
bio = binject_map_bio(q, bd->bdev, uc->buf, uc->len,
!ucm->todevice, GFP_KERNEL);
} else {
- bio = bio_alloc(GFP_KERNEL, uc->len / PAGE_SIZE);
+ bio = bio_alloc(GFP_KERNEL, len_to_pages(uc->len));
if (bio) {
bio->bi_bdev = bd->bdev;
- if (ucm->todevice)
- binject_mark_bio_write(bio);
if (ucm->map_zero && uc->len) {
int err;
else if (!IS_ERR(bio)) {
map_uc_to_bio_flags(bio, uc);
bio->bi_sector = uc->offset / binject_get_bs(q);
+ bio->bi_rw |= ucm->rw_flags;
}
return bio;
struct b_dev *bd;
rcu_read_lock();
+
bd = idr_find(&b_minor_idr, minor);
- if (bd) {
- if (!atomic_inc_not_zero(&bd->ref))
- bd = NULL;
- }
- rcu_read_unlock();
+ if (bd && !atomic_inc_not_zero(&bd->ref))
+ bd = NULL;
+ rcu_read_unlock();
return bd;
}
size_t count, loff_t *ppos)
{
struct b_dev *bd = file->private_data;
+ struct b_cmd *bc = NULL;
unsigned int total;
ssize_t done = 0;
int err = 0;
total = count / sizeof(struct b_user_cmd);
while (total) {
- struct b_cmd *bc;
-
bc = get_free_command(bd);
if (IS_ERR(bc)) {
err = PTR_ERR(bc);
+ bc = NULL;
break;
}
}
err = b_dev_validate_command(&bc->cmd);
- if (err) {
- b_dev_free_command(bd, bc);
+ if (err)
break;
- }
err = b_dev_add_command(bd, bc);
- if (err) {
- b_dev_free_command(bd, bc);
+ if (err)
break;
- }
done += sizeof(struct b_user_cmd);
buf += sizeof(struct b_user_cmd);
total--;
}
+ if (bc)
+ b_dev_free_command(bd, bc);
+
*ppos = done;
if (!done)
done = err;