hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// 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;
}