On Sat, 23 Jan 2021 18:24:24 +0900 Bongsu Jeon wrote: > From: Bongsu Jeon <bongsu.jeon@xxxxxxxxxxx> > > NCI virtual device simulates a NCI device to the user. It can be used to > validate the NCI module and applications. This driver supports > communication between the virtual NCI device and NCI module. > > Signed-off-by: Bongsu Jeon <bongsu.jeon@xxxxxxxxxxx> > +static bool virtual_ncidev_check_enabled(void) > +{ > + bool ret = true; > + > + mutex_lock(&nci_mutex); > + if (state != virtual_ncidev_enabled) > + ret = false; > + mutex_unlock(&nci_mutex); > + > + return ret; This can be simplified like: bool ret; mutex_lock() ret = state == virtual_ncidev_enabled; mutex_unlock() return ret; > +} > + > +static int virtual_nci_open(struct nci_dev *ndev) > +{ > + return 0; > +} > + > +static int virtual_nci_close(struct nci_dev *ndev) > +{ > + mutex_lock(&nci_mutex); > + if (send_buff) > + kfree_skb(send_buff); kfree_skb() handles NULL, no need for the if, you can always call kfree_skb() here > + send_buff = NULL; > + mutex_unlock(&nci_mutex); > + > + return 0; > +} > + > +static int virtual_nci_send(struct nci_dev *ndev, struct sk_buff *skb) > +{ > + if (virtual_ncidev_check_enabled() == false) > + return 0; Shouldn't you check this _under_ the lock below? Otherwise there is a small window between check and use of send_buff > + mutex_lock(&nci_mutex); > + if (send_buff) { > + mutex_unlock(&nci_mutex); > + return -1; > + } > + send_buff = skb_copy(skb, GFP_KERNEL); > + mutex_unlock(&nci_mutex); > + > + return 0; > +} > + > +static struct nci_ops virtual_nci_ops = { > + .open = virtual_nci_open, > + .close = virtual_nci_close, > + .send = virtual_nci_send > +}; > + > +static ssize_t virtual_ncidev_read(struct file *file, char __user *buf, > + size_t count, loff_t *ppos) > +{ > + size_t actual_len; > + > + mutex_lock(&nci_mutex); > + if (!send_buff) { > + mutex_unlock(&nci_mutex); > + return 0; > + } > + > + actual_len = min_t(size_t, count, send_buff->len); > + > + if (copy_to_user(buf, send_buff->data, actual_len)) { > + mutex_unlock(&nci_mutex); > + return -EFAULT; > + } > + > + skb_pull(send_buff, actual_len); > + if (send_buff->len == 0) { > + consume_skb(send_buff); > + send_buff = NULL; > + } > + mutex_unlock(&nci_mutex); > + > + return actual_len; > +} > + > +static ssize_t virtual_ncidev_write(struct file *file, > + const char __user *buf, > + size_t count, loff_t *ppos) > +{ > + struct sk_buff *skb; > + > + skb = alloc_skb(count, GFP_KERNEL); > + if (!skb) > + return -ENOMEM; > + > + if (copy_from_user(skb_put(skb, count), buf, count)) { > + kfree_skb(skb); > + return -EFAULT; > + } > + > + nci_recv_frame(ndev, skb); > + return count; > +} > + > +static int virtual_ncidev_open(struct inode *inode, struct file *file) > +{ > + int ret = 0; > + > + mutex_lock(&nci_mutex); > + if (state != virtual_ncidev_disabled) { > + mutex_unlock(&nci_mutex); > + return -EBUSY; > + } > + > + ndev = nci_allocate_device(&virtual_nci_ops, VIRTUAL_NFC_PROTOCOLS, > + 0, 0); > + if (!ndev) { > + mutex_unlock(&nci_mutex); > + return -ENOMEM; > + } > + > + ret = nci_register_device(ndev); > + if (ret < 0) { > + nci_free_device(ndev); > + mutex_unlock(&nci_mutex); > + return ret; > + } > + state = virtual_ncidev_enabled; > + mutex_unlock(&nci_mutex); > + > + return 0; > +} > + > +static int virtual_ncidev_close(struct inode *inode, struct file *file) > +{ > + mutex_lock(&nci_mutex); > + > + if (state == virtual_ncidev_enabled) { > + state = virtual_ncidev_disabling; > + mutex_unlock(&nci_mutex); > + > + nci_unregister_device(ndev); > + nci_free_device(ndev); > + > + mutex_lock(&nci_mutex); > + } > + > + state = virtual_ncidev_disabled; > + mutex_unlock(&nci_mutex); > + > + return 0; > +} > + > +static long virtual_ncidev_ioctl(struct file *flip, unsigned int cmd, > + unsigned long arg) > +{ > + if (cmd == IOCTL_GET_NCIDEV_IDX) { > + struct nfc_dev *nfc_dev = ndev->nfc_dev; > + void __user *p = (void __user *)arg; > + > + if (copy_to_user(p, &nfc_dev->idx, sizeof(nfc_dev->idx))) > + return -EFAULT; > + } else { > + return -ENOTTY; > + } > + > + return 0; Please flip the condition and return early. I think I suggested this already: { struct nfc_dev *nfc_dev = ndev->nfc_dev; void __user *p = (void __user *)arg; if (cmd != IOCTL_GET_NCIDEV_IDX) return -ENOTTY; if (copy_to_user(p, &nfc_dev->idx, sizeof(nfc_dev->idx))) return -EFAULT; return 0;