forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
103 lines
2.3 KiB
103 lines
2.3 KiB
// SPDX-License-Identifier: GPL-2.0-or-later |
|
/* |
|
* RDMA Network Block Driver |
|
* |
|
* Copyright (c) 2014 - 2018 ProfitBricks GmbH. All rights reserved. |
|
* Copyright (c) 2018 - 2019 1&1 IONOS Cloud GmbH. All rights reserved. |
|
* Copyright (c) 2019 - 2020 1&1 IONOS SE. All rights reserved. |
|
*/ |
|
#undef pr_fmt |
|
#define pr_fmt(fmt) KBUILD_MODNAME " L" __stringify(__LINE__) ": " fmt |
|
|
|
#include "rnbd-srv-dev.h" |
|
#include "rnbd-log.h" |
|
|
|
struct rnbd_dev *rnbd_dev_open(const char *path, fmode_t flags, |
|
struct bio_set *bs) |
|
{ |
|
struct rnbd_dev *dev; |
|
int ret; |
|
|
|
dev = kzalloc(sizeof(*dev), GFP_KERNEL); |
|
if (!dev) |
|
return ERR_PTR(-ENOMEM); |
|
|
|
dev->blk_open_flags = flags; |
|
dev->bdev = blkdev_get_by_path(path, flags, THIS_MODULE); |
|
ret = PTR_ERR_OR_ZERO(dev->bdev); |
|
if (ret) |
|
goto err; |
|
|
|
dev->blk_open_flags = flags; |
|
bdevname(dev->bdev, dev->name); |
|
dev->ibd_bio_set = bs; |
|
|
|
return dev; |
|
|
|
err: |
|
kfree(dev); |
|
return ERR_PTR(ret); |
|
} |
|
|
|
void rnbd_dev_close(struct rnbd_dev *dev) |
|
{ |
|
blkdev_put(dev->bdev, dev->blk_open_flags); |
|
kfree(dev); |
|
} |
|
|
|
void rnbd_dev_bi_end_io(struct bio *bio) |
|
{ |
|
struct rnbd_dev_blk_io *io = bio->bi_private; |
|
|
|
rnbd_endio(io->priv, blk_status_to_errno(bio->bi_status)); |
|
bio_put(bio); |
|
} |
|
|
|
/** |
|
* rnbd_bio_map_kern - map kernel address into bio |
|
* @data: pointer to buffer to map |
|
* @bs: bio_set to use. |
|
* @len: length in bytes |
|
* @gfp_mask: allocation flags for bio allocation |
|
* |
|
* Map the kernel address into a bio suitable for io to a block |
|
* device. Returns an error pointer in case of error. |
|
*/ |
|
struct bio *rnbd_bio_map_kern(void *data, struct bio_set *bs, |
|
unsigned int len, gfp_t gfp_mask) |
|
{ |
|
unsigned long kaddr = (unsigned long)data; |
|
unsigned long end = (kaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT; |
|
unsigned long start = kaddr >> PAGE_SHIFT; |
|
const int nr_pages = end - start; |
|
int offset, i; |
|
struct bio *bio; |
|
|
|
bio = bio_alloc_bioset(gfp_mask, nr_pages, bs); |
|
if (!bio) |
|
return ERR_PTR(-ENOMEM); |
|
|
|
offset = offset_in_page(kaddr); |
|
for (i = 0; i < nr_pages; i++) { |
|
unsigned int bytes = PAGE_SIZE - offset; |
|
|
|
if (len <= 0) |
|
break; |
|
|
|
if (bytes > len) |
|
bytes = len; |
|
|
|
if (bio_add_page(bio, virt_to_page(data), bytes, |
|
offset) < bytes) { |
|
/* we don't support partial mappings */ |
|
bio_put(bio); |
|
return ERR_PTR(-EINVAL); |
|
} |
|
|
|
data += bytes; |
|
len -= bytes; |
|
offset = 0; |
|
} |
|
|
|
return bio; |
|
}
|
|
|