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 /drivers | |
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>
Diffstat (limited to 'drivers')
-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; |