On 6/20/19 8:03 AM, Jack Wang wrote:
+#undef pr_fmt
+#define pr_fmt(fmt) KBUILD_MODNAME " L" __stringify(__LINE__) ": " fmt

Same comment as for a previous patch: please do not include line number information in pr_fmt().

+static int ibnbd_dev_vfs_open(struct ibnbd_dev *dev, const char *path,
+                             fmode_t flags)
+{
+       int oflags = O_DSYNC; /* enable write-through */
+
+       if (flags & FMODE_WRITE)
+               oflags |= O_RDWR;
+       else if (flags & FMODE_READ)
+               oflags |= O_RDONLY;
+       else
+               return -EINVAL;
+
+       dev->file = filp_open(path, oflags, 0);
+       return PTR_ERR_OR_ZERO(dev->file);
+}

Isn't the use of O_DSYNC something that should be configurable?

+struct ibnbd_dev *ibnbd_dev_open(const char *path, fmode_t flags,
+                                enum ibnbd_io_mode mode, struct bio_set *bs,
+                                ibnbd_dev_io_fn io_cb)
+{
+       struct ibnbd_dev *dev;
+       int ret;
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return ERR_PTR(-ENOMEM);
+
+       if (mode == IBNBD_BLOCKIO) {
+               dev->blk_open_flags = flags;
+               ret = ibnbd_dev_blk_open(dev, path, dev->blk_open_flags);
+               if (ret)
+                       goto err;
+       } else if (mode == IBNBD_FILEIO) {
+               dev->blk_open_flags = FMODE_READ;
+               ret = ibnbd_dev_blk_open(dev, path, dev->blk_open_flags);
+               if (ret)
+                       goto err;
+
+               ret = ibnbd_dev_vfs_open(dev, path, flags);
+               if (ret)
+                       goto blk_put;

This looks really weird. Why to call ibnbd_dev_blk_open() first for file I/O mode? Why to set dev->blk_open_flags to FMODE_READ in file I/O mode?

+static int ibnbd_dev_blk_submit_io(struct ibnbd_dev *dev, sector_t sector,
+                                  void *data, size_t len, u32 bi_size,
+                                  enum ibnbd_io_flags flags, short prio,
+                                  void *priv)
+{
+       struct request_queue *q = bdev_get_queue(dev->bdev);
+       struct ibnbd_dev_blk_io *io;
+       struct bio *bio;
+
+       /* check if the buffer is suitable for bdev */
+       if (unlikely(WARN_ON(!blk_rq_aligned(q, (unsigned long)data, len))))
+               return -EINVAL;
+
+       /* Generate bio with pages pointing to the rdma buffer */
+       bio = ibnbd_bio_map_kern(q, data, dev->ibd_bio_set, len, GFP_KERNEL);
+       if (unlikely(IS_ERR(bio)))
+               return PTR_ERR(bio);
+
+       io = kmalloc(sizeof(*io), GFP_KERNEL);
+       if (unlikely(!io)) {
+               bio_put(bio);
+               return -ENOMEM;
+       }
+
+       io->dev              = dev;
+       io->priv     = priv;
+
+       bio->bi_end_io               = ibnbd_dev_bi_end_io;
+       bio->bi_private              = io;
+       bio->bi_opf          = ibnbd_to_bio_flags(flags);
+       bio->bi_iter.bi_sector       = sector;
+       bio->bi_iter.bi_size = bi_size;
+       bio_set_prio(bio, prio);
+       bio_set_dev(bio, dev->bdev);
+
+       submit_bio(bio);
+
+       return 0;
+}

Can struct bio and struct ibnbd_dev_blk_io be combined into a single data structure by passing the size of the latter data structure as the front_pad argument to bioset_init()?

+static void ibnbd_dev_file_submit_io_worker(struct work_struct *w)
+{
+       struct ibnbd_dev_file_io_work *dev_work;
+       struct file *f;
+       int ret, len;
+       loff_t off;
+
+       dev_work = container_of(w, struct ibnbd_dev_file_io_work, work);
+       off = dev_work->sector * ibnbd_dev_get_logical_bsize(dev_work->dev);
+       f = dev_work->dev->file;
+       len = dev_work->bi_size;
+
+       if (ibnbd_op(dev_work->flags) == IBNBD_OP_FLUSH) {
+               ret = ibnbd_dev_file_handle_flush(dev_work, off);
+               if (unlikely(ret))
+                       goto out;
+       }
+
+       if (ibnbd_op(dev_work->flags) == IBNBD_OP_WRITE_SAME) {
+               ret = ibnbd_dev_file_handle_write_same(dev_work);
+               if (unlikely(ret))
+                       goto out;
+       }
+
+       /* TODO Implement support for DIRECT */
+       if (dev_work->bi_size) {
+               loff_t off_tmp = off;
+
+               if (ibnbd_op(dev_work->flags) == IBNBD_OP_WRITE)
+                       ret = kernel_write(f, dev_work->data, dev_work->bi_size,
+                                          &off_tmp);
+               else
+                       ret = kernel_read(f, dev_work->data, dev_work->bi_size,
+                                         &off_tmp);
+
+               if (unlikely(ret < 0)) {
+                       goto out;
+               } else if (unlikely(ret != dev_work->bi_size)) {
+                       /* TODO implement support for partial completions */
+                       ret = -EIO;
+                       goto out;
+               } else {
+                       ret = 0;
+               }
+       }
+
+       if (dev_work->flags & IBNBD_F_FUA)
+               ret = ibnbd_dev_file_handle_fua(dev_work, off);
+out:
+       dev_work->dev->io_cb(dev_work->priv, ret);
+       kfree(dev_work);
+}
+
+static int ibnbd_dev_file_submit_io(struct ibnbd_dev *dev, sector_t sector,
+                                   void *data, size_t len, size_t bi_size,
+                                   enum ibnbd_io_flags flags, void *priv)
+{
+       struct ibnbd_dev_file_io_work *w;
+
+       if (!ibnbd_flags_supported(flags)) {
+               pr_info_ratelimited("Unsupported I/O flags: 0x%x on device "
+                                   "%s\n", flags, dev->name);
+               return -ENOTSUPP;
+       }
+
+       w = kmalloc(sizeof(*w), GFP_KERNEL);
+       if (!w)
+               return -ENOMEM;
+
+       w->dev               = dev;
+       w->priv              = priv;
+       w->sector    = sector;
+       w->data              = data;
+       w->len               = len;
+       w->bi_size   = bi_size;
+       w->flags     = flags;
+       INIT_WORK(&w->work, ibnbd_dev_file_submit_io_worker);
+
+       if (unlikely(!queue_work(fileio_wq, &w->work))) {
+               kfree(w);
+               return -EEXIST;
+       }
+
+       return 0;
+}

Please use the in-kernel asynchronous I/O API instead of kernel_read() and kernel_write() and remove the fileio_wq workqueue. Examples of how to use call_read_iter() and call_write_iter() are available in the loop driver and also in drivers/target/target_core_file.c.

+/** ibnbd_dev_init() - Initialize ibnbd_dev
+ *
+ * This functions initialized the ibnbd-dev component.
+ * It has to be called 1x time before ibnbd_dev_open() is used
+ */
+int ibnbd_dev_init(void);

It is great so see kernel-doc headers above functions but I'm not sure these should be in .h files. I think most kernel developers prefer to see kernel-doc headers for functions in .c files because that makes it more likely that the implementation and the documentation stay in sync.

Thanks,

Bart.

Reply via email to