diff options
| author | Oliver Neukum <oliver@neukum.org> | 2005-12-21 13:27:29 -0500 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-01-04 16:51:44 -0500 |
| commit | ff90651883093576de2d60bebaae39b0dd2e62f6 (patch) | |
| tree | 8029f0742384a7f22fbd4175cf9a73194eee33d6 | |
| parent | aafbf24a1129480157af7ee780eddcea9b76ee5c (diff) | |
[PATCH] USB: Limiting of resource use in skeleton driver
this introduces limits whose lack in the skeleton driver someone recently
complained about.
Signed-off-by: Oliver Neukum <oliver@neukum.name>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
| -rw-r--r-- | drivers/usb/usb-skeleton.c | 25 |
1 files changed, 18 insertions, 7 deletions
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index 60c458ebaa2d..719d23a4ac51 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c | |||
| @@ -39,10 +39,15 @@ MODULE_DEVICE_TABLE (usb, skel_table); | |||
| 39 | /* Get a minor range for your devices from the usb maintainer */ | 39 | /* Get a minor range for your devices from the usb maintainer */ |
| 40 | #define USB_SKEL_MINOR_BASE 192 | 40 | #define USB_SKEL_MINOR_BASE 192 |
| 41 | 41 | ||
| 42 | /* our private defines. if this grows any larger, use your own .h file */ | ||
| 43 | #define MAX_TRANSFER ( PAGE_SIZE - 512 ) | ||
| 44 | #define WRITES_IN_FLIGHT 8 | ||
| 45 | |||
| 42 | /* Structure to hold all of our device specific stuff */ | 46 | /* Structure to hold all of our device specific stuff */ |
| 43 | struct usb_skel { | 47 | struct usb_skel { |
| 44 | struct usb_device * udev; /* the usb device for this device */ | 48 | struct usb_device * udev; /* the usb device for this device */ |
| 45 | struct usb_interface * interface; /* the interface for this device */ | 49 | struct usb_interface * interface; /* the interface for this device */ |
| 50 | struct semaphore limit_sem; /* limiting the number of writes in progress */ | ||
| 46 | unsigned char * bulk_in_buffer; /* the buffer to receive data */ | 51 | unsigned char * bulk_in_buffer; /* the buffer to receive data */ |
| 47 | size_t bulk_in_size; /* the size of the receive buffer */ | 52 | size_t bulk_in_size; /* the size of the receive buffer */ |
| 48 | __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ | 53 | __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ |
| @@ -152,6 +157,7 @@ static void skel_write_bulk_callback(struct urb *urb, struct pt_regs *regs) | |||
| 152 | /* free up our allocated buffer */ | 157 | /* free up our allocated buffer */ |
| 153 | usb_buffer_free(urb->dev, urb->transfer_buffer_length, | 158 | usb_buffer_free(urb->dev, urb->transfer_buffer_length, |
| 154 | urb->transfer_buffer, urb->transfer_dma); | 159 | urb->transfer_buffer, urb->transfer_dma); |
| 160 | up(&dev->limit_sem); | ||
| 155 | } | 161 | } |
| 156 | 162 | ||
| 157 | static ssize_t skel_write(struct file *file, const char *user_buffer, size_t count, loff_t *ppos) | 163 | static ssize_t skel_write(struct file *file, const char *user_buffer, size_t count, loff_t *ppos) |
| @@ -160,6 +166,7 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou | |||
| 160 | int retval = 0; | 166 | int retval = 0; |
| 161 | struct urb *urb = NULL; | 167 | struct urb *urb = NULL; |
| 162 | char *buf = NULL; | 168 | char *buf = NULL; |
| 169 | size_t writesize = max(count, MAX_TRANSFER); | ||
| 163 | 170 | ||
| 164 | dev = (struct usb_skel *)file->private_data; | 171 | dev = (struct usb_skel *)file->private_data; |
| 165 | 172 | ||
| @@ -167,6 +174,9 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou | |||
| 167 | if (count == 0) | 174 | if (count == 0) |
| 168 | goto exit; | 175 | goto exit; |
| 169 | 176 | ||
| 177 | /* limit the number of URBs in flight to stop a user from using up all RAM */ | ||
| 178 | down (&dev->limit_sem); | ||
| 179 | |||
| 170 | /* create a urb, and a buffer for it, and copy the data to the urb */ | 180 | /* create a urb, and a buffer for it, and copy the data to the urb */ |
| 171 | urb = usb_alloc_urb(0, GFP_KERNEL); | 181 | urb = usb_alloc_urb(0, GFP_KERNEL); |
| 172 | if (!urb) { | 182 | if (!urb) { |
| @@ -174,13 +184,13 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou | |||
| 174 | goto error; | 184 | goto error; |
| 175 | } | 185 | } |
| 176 | 186 | ||
| 177 | buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL, &urb->transfer_dma); | 187 | buf = usb_buffer_alloc(dev->udev, writesize, GFP_KERNEL, &urb->transfer_dma); |
| 178 | if (!buf) { | 188 | if (!buf) { |
| 179 | retval = -ENOMEM; | 189 | retval = -ENOMEM; |
| 180 | goto error; | 190 | goto error; |
| 181 | } | 191 | } |
| 182 | 192 | ||
| 183 | if (copy_from_user(buf, user_buffer, count)) { | 193 | if (copy_from_user(buf, user_buffer, writesize)) { |
| 184 | retval = -EFAULT; | 194 | retval = -EFAULT; |
| 185 | goto error; | 195 | goto error; |
| 186 | } | 196 | } |
| @@ -188,7 +198,7 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou | |||
| 188 | /* initialize the urb properly */ | 198 | /* initialize the urb properly */ |
| 189 | usb_fill_bulk_urb(urb, dev->udev, | 199 | usb_fill_bulk_urb(urb, dev->udev, |
| 190 | usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), | 200 | usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), |
| 191 | buf, count, skel_write_bulk_callback, dev); | 201 | buf, writesize, skel_write_bulk_callback, dev); |
| 192 | urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | 202 | urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
| 193 | 203 | ||
| 194 | /* send the data out the bulk port */ | 204 | /* send the data out the bulk port */ |
| @@ -202,11 +212,12 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou | |||
| 202 | usb_free_urb(urb); | 212 | usb_free_urb(urb); |
| 203 | 213 | ||
| 204 | exit: | 214 | exit: |
| 205 | return count; | 215 | return writesize; |
| 206 | 216 | ||
| 207 | error: | 217 | error: |
| 208 | usb_buffer_free(dev->udev, count, buf, urb->transfer_dma); | 218 | usb_buffer_free(dev->udev, writesize, buf, urb->transfer_dma); |
| 209 | usb_free_urb(urb); | 219 | usb_free_urb(urb); |
| 220 | up(&dev->limit_sem); | ||
| 210 | return retval; | 221 | return retval; |
| 211 | } | 222 | } |
| 212 | 223 | ||
| @@ -238,13 +249,13 @@ static int skel_probe(struct usb_interface *interface, const struct usb_device_i | |||
| 238 | int retval = -ENOMEM; | 249 | int retval = -ENOMEM; |
| 239 | 250 | ||
| 240 | /* allocate memory for our device state and initialize it */ | 251 | /* allocate memory for our device state and initialize it */ |
| 241 | dev = kmalloc(sizeof(*dev), GFP_KERNEL); | 252 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); |
| 242 | if (dev == NULL) { | 253 | if (dev == NULL) { |
| 243 | err("Out of memory"); | 254 | err("Out of memory"); |
| 244 | goto error; | 255 | goto error; |
| 245 | } | 256 | } |
| 246 | memset(dev, 0x00, sizeof(*dev)); | ||
| 247 | kref_init(&dev->kref); | 257 | kref_init(&dev->kref); |
| 258 | sema_init(&dev->limit_sem, WRITES_IN_FLIGHT); | ||
| 248 | 259 | ||
| 249 | dev->udev = usb_get_dev(interface_to_usbdev(interface)); | 260 | dev->udev = usb_get_dev(interface_to_usbdev(interface)); |
| 250 | dev->interface = interface; | 261 | dev->interface = interface; |
