Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Bluetooth: Add support for vectored writes to virtual HCI driver

The Bluetooth virtual HCI driver is using a misc character device to
allow emulation of HCI devices from userspace. This change enables the
support for vectored writes. Previously this was failing with EINVAL
since no complete H:4 packet was written.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>

authored by

Marcel Holtmann and committed by
Johan Hedberg
5bc00b5c de8b5828

+18 -11
+18 -11
drivers/bluetooth/hci_vhci.c
··· 141 141 } 142 142 143 143 static inline ssize_t vhci_get_user(struct vhci_data *data, 144 - const char __user *buf, size_t count) 144 + const struct iovec *iov, 145 + unsigned long count) 145 146 { 147 + size_t len = iov_length(iov, count); 146 148 struct sk_buff *skb; 147 149 __u8 pkt_type, dev_type; 150 + unsigned long i; 148 151 int ret; 149 152 150 - if (count < 2 || count > HCI_MAX_FRAME_SIZE) 153 + if (len < 2 || len > HCI_MAX_FRAME_SIZE) 151 154 return -EINVAL; 152 155 153 - skb = bt_skb_alloc(count, GFP_KERNEL); 156 + skb = bt_skb_alloc(len, GFP_KERNEL); 154 157 if (!skb) 155 158 return -ENOMEM; 156 159 157 - if (copy_from_user(skb_put(skb, count), buf, count)) { 158 - kfree_skb(skb); 159 - return -EFAULT; 160 + for (i = 0; i < count; i++) { 161 + if (copy_from_user(skb_put(skb, iov[i].iov_len), 162 + iov[i].iov_base, iov[i].iov_len)) { 163 + kfree_skb(skb); 164 + return -EFAULT; 165 + } 160 166 } 161 167 162 168 pkt_type = *((__u8 *) skb->data); ··· 211 205 return -EINVAL; 212 206 } 213 207 214 - return (ret < 0) ? ret : count; 208 + return (ret < 0) ? ret : len; 215 209 } 216 210 217 211 static inline ssize_t vhci_put_user(struct vhci_data *data, ··· 278 272 return ret; 279 273 } 280 274 281 - static ssize_t vhci_write(struct file *file, 282 - const char __user *buf, size_t count, loff_t *pos) 275 + static ssize_t vhci_write(struct kiocb *iocb, const struct iovec *iov, 276 + unsigned long count, loff_t pos) 283 277 { 278 + struct file *file = iocb->ki_filp; 284 279 struct vhci_data *data = file->private_data; 285 280 286 - return vhci_get_user(data, buf, count); 281 + return vhci_get_user(data, iov, count); 287 282 } 288 283 289 284 static unsigned int vhci_poll(struct file *file, poll_table *wait) ··· 349 342 static const struct file_operations vhci_fops = { 350 343 .owner = THIS_MODULE, 351 344 .read = vhci_read, 352 - .write = vhci_write, 345 + .aio_write = vhci_write, 353 346 .poll = vhci_poll, 354 347 .open = vhci_open, 355 348 .release = vhci_release,