Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
View | Details | Raw Unified | Return to bug 96449 | Differences between
and this patch

Collapse All | Expand All

(-)fusd-kor-1.10-11/kfusd/kfusd.c (-2067 / +2080 lines)
Lines 1-6 Link Here
1
/*
1
/*
2
 *
2
 *
3
 * Copyright (c) 2003 The Regents of the University of California.  All 
3
 * Copyright (c) 2003 The Regents of the University of California. All
4
 * rights reserved.
4
 * rights reserved.
5
 *
5
 *
6
 * Redistribution and use in source and binary forms, with or without
6
 * Redistribution and use in source and binary forms, with or without
Lines 8-23 Link Here
8
 * are met:
8
 * are met:
9
 *
9
 *
10
 * - Redistributions of source code must retain the above copyright
10
 * - Redistributions of source code must retain the above copyright
11
 *   notice, this list of conditions and the following disclaimer.
11
 * notice, this list of conditions and the following disclaimer.
12
 *
12
 *
13
 * - Neither the name of the University nor the names of its
13
 * - Neither the name of the University nor the names of its
14
 *   contributors may be used to endorse or promote products derived
14
 * contributors may be used to endorse or promote products derived
15
 *   from this software without specific prior written permission.
15
 * from this software without specific prior written permission.
16
 *
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
17
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
18
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
19
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20
 * PARTICULAR  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
20
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
21
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
Lines 27-40 Link Here
27
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
 *
28
 *
29
 */
29
 */
30
 
30
31
31
32
/*
32
/*
33
 * FUSD: the Framework for User-Space Devices
33
 * FUSD: the Framework for User-Space Devices
34
 *
34
 *
35
 * Linux Kernel Module
35
 * Linux Kernel Module
36
 *
36
 *
37
 * Jeremy Elson  <jelson@circlemud.org>
37
 * Jeremy Elson <jelson@circlemud.org>
38
 * Copyright (c) 2001, Sensoria Corporation
38
 * Copyright (c) 2001, Sensoria Corporation
39
 * Copyright (c) 2002-2003, Regents of the University of California
39
 * Copyright (c) 2002-2003, Regents of the University of California
40
 *
40
 *
Lines 43-49 Link Here
43
43
44
/*
44
/*
45
 * Note on debugging messages: Unexpected errors (i.e., indicators of
45
 * Note on debugging messages: Unexpected errors (i.e., indicators of
46
 * bugs in this kernel module) should always contain '!'.  Expected
46
 * bugs in this kernel module) should always contain '!'. Expected
47
 * conditions, even if exceptional (e.g., the device-driver-provider
47
 * conditions, even if exceptional (e.g., the device-driver-provider
48
 * disappears while a file is waiting for a return from a system call)
48
 * disappears while a file is waiting for a return from a system call)
49
 * must NOT contain '!'.
49
 * must NOT contain '!'.
Lines 57-63 Link Here
57
#include <linux/modversions.h>
57
#include <linux/modversions.h>
58
#endif
58
#endif
59
59
60
#include <linux/config.h>
60
//#include <linux/config.h>
61
#include <linux/stddef.h>
61
#include <linux/stddef.h>
62
#include <linux/kernel.h>
62
#include <linux/kernel.h>
63
#include <linux/module.h>
63
#include <linux/module.h>
Lines 67-73 Link Here
67
#include <linux/mm.h>
67
#include <linux/mm.h>
68
#include <linux/slab.h>
68
#include <linux/slab.h>
69
#include <linux/vmalloc.h>
69
#include <linux/vmalloc.h>
70
#include <linux/devfs_fs_kernel.h>
70
//#include <linux/devfs_fs_kernel.h>
71
#include <linux/poll.h>
71
#include <linux/poll.h>
72
#include <linux/version.h>
72
#include <linux/version.h>
73
#include <linux/major.h>
73
#include <linux/major.h>
Lines 87-103 Link Here
87
/* Define this if you want to emit debug messages (adds ~8K) */
87
/* Define this if you want to emit debug messages (adds ~8K) */
88
#define CONFIG_FUSD_DEBUG
88
#define CONFIG_FUSD_DEBUG
89
89
90
/* Default debug level for FUSD messages.  Has no effect unless
90
/* Default debug level for FUSD messages. Has no effect unless
91
 * CONFIG_FUSD_DEBUG is defined. */
91
 * CONFIG_FUSD_DEBUG is defined. */
92
#ifndef CONFIG_FUSD_DEBUGLEVEL
92
#ifndef CONFIG_FUSD_DEBUGLEVEL
93
#define CONFIG_FUSD_DEBUGLEVEL 2
93
#define CONFIG_FUSD_DEBUGLEVEL 10
94
#endif
94
#endif
95
95
96
/* Define this to check for memory leaks */
96
/* Define this to check for memory leaks */
97
/*#define CONFIG_FUSD_MEMDEBUG*/
97
/*#define CONFIG_FUSD_MEMDEBUG*/
98
98
99
/* Define this to use the faster wake_up_interruptible_sync instead of
99
/* Define this to use the faster wake_up_interruptible_sync instead of
100
 * the normal wake_up_interruptible.  Note: you can't do this unless
100
 * the normal wake_up_interruptible. Note: you can't do this unless
101
 * you're bulding fusd as part of the kernel (not a module); or you've
101
 * you're bulding fusd as part of the kernel (not a module); or you've
102
 * patched kernel/ksyms.s to add __wake_up_sync in addition to
102
 * patched kernel/ksyms.s to add __wake_up_sync in addition to
103
 * __wake_up. */
103
 * __wake_up. */
Lines 105-111 Link Here
105
105
106
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,9)
106
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,9)
107
# define vsnprintf(str, size, format, ap) vsprintf(str, format, ap)
107
# define vsnprintf(str, size, format, ap) vsprintf(str, format, ap)
108
# define  snprintf(str, len, args...)      sprintf(str, args)
108
# define snprintf(str, len, args...) sprintf(str, args)
109
#endif
109
#endif
110
110
111
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
111
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
Lines 178-212 Link Here
178
#ifdef CONFIG_FUSD_DEBUG
178
#ifdef CONFIG_FUSD_DEBUG
179
179
180
STATIC int fusd_debug_level = CONFIG_FUSD_DEBUGLEVEL;
180
STATIC int fusd_debug_level = CONFIG_FUSD_DEBUGLEVEL;
181
MODULE_PARM(fusd_debug_level, "i");
181
MODULE_PARM_DESC(fusd_debug_level, "i");
182
182
183
#define BUFSIZE 1000 /* kernel's kmalloc pool has a 1012-sized bucket */
183
#define BUFSIZE 1000 /* kernel's kmalloc pool has a 1012-sized bucket */
184
184
185
STATIC void rdebug_real(char *fmt, ...)
185
STATIC void rdebug_real(char *fmt, ...)
186
{
186
{
187
  va_list ap;
187
 va_list ap;
188
  int len;
188
 int len;
189
  char *message;
189
 char *message;
190
190
191
  /* I'm kmallocing since you don't really want 1k on the stack. I've
191
 /* I'm kmallocing since you don't really want 1k on the stack. I've
192
   * had stack overflow problems before; the kernel stack is quite
192
 * had stack overflow problems before; the kernel stack is quite
193
   * small... */
193
 * small... */
194
  if ((message = KMALLOC(BUFSIZE, GFP_KERNEL)) == NULL)
194
 if ((message = KMALLOC(BUFSIZE, GFP_KERNEL)) == NULL)
195
    return;
195
 return;
196
196
197
  va_start(ap, fmt);
197
 va_start(ap, fmt);
198
  len = vsnprintf(message, BUFSIZE-1, fmt, ap);
198
 len = vsnprintf(message, BUFSIZE-1, fmt, ap);
199
  va_end(ap);
199
 va_end(ap);
200
200
201
  if (len >= BUFSIZE) {
201
 if (len >= BUFSIZE) {
202
    printk("WARNING: POSSIBLE KERNEL CORRUPTION; MESSAGE TOO LONG\n");
202
 printk("WARNING: POSSIBLE KERNEL CORRUPTION; MESSAGE TOO LONG\n");
203
  } else {
203
 } else {
204
    printk("fusd: %.975s\n", message); /* note msgs are truncated at
204
 printk("fusd: %.975s\n", message); /* note msgs are truncated at
205
                      * ~1000 chars to fit inside the 1024 printk
205
 * ~1000 chars to fit inside the 1024 printk
206
                      * limit imposed by the kernel */
206
 * limit imposed by the kernel */
207
  }
207
 }
208
208
209
  KFREE(message);
209
 KFREE(message);
210
}
210
}
211
211
212
#endif /* CONFIG_FUSD_DEBUG */
212
#endif /* CONFIG_FUSD_DEBUG */
Lines 220-329 Link Here
220
DECLARE_MUTEX(fusd_memdebug_sem);
220
DECLARE_MUTEX(fusd_memdebug_sem);
221
221
222
typedef struct {
222
typedef struct {
223
  void *ptr;
223
 void *ptr;
224
  int line;
224
 int line;
225
  int size;
225
 int size;
226
} mem_debug_t;
226
} mem_debug_t;
227
227
228
mem_debug_t *mem_debug;
228
mem_debug_t *mem_debug;
229
229
230
STATIC int fusd_mem_init(void)
230
STATIC int fusd_mem_init(void)
231
{
231
{
232
  int i;
232
 int i;
233
233
234
  mem_debug = kmalloc(sizeof(mem_debug_t) * MAX_MEM_DEBUG, GFP_KERNEL);
234
 mem_debug = kmalloc(sizeof(mem_debug_t) * MAX_MEM_DEBUG, GFP_KERNEL);
235
235
236
  if (mem_debug == NULL) {
236
 if (mem_debug == NULL) {
237
    RDEBUG(2, "argh - memdebug malloc failed!");
237
 RDEBUG(2, "argh - memdebug malloc failed!");
238
    return -ENOMEM;
238
 return -ENOMEM;
239
  }
239
 }
240
240
241
  /* initialize */
241
 /* initialize */
242
  for (i = 0; i < MAX_MEM_DEBUG; i++)
242
 for (i = 0; i < MAX_MEM_DEBUG; i++)
243
    mem_debug[i].ptr = NULL;
243
 mem_debug[i].ptr = NULL;
244
244
245
  RDEBUG(2, "FUSD memory debugger activated");
245
 RDEBUG(2, "FUSD memory debugger activated");
246
  return 0;
246
 return 0;
247
}
247
}
248
248
249
STATIC void fusd_mem_cleanup(void)
249
STATIC void fusd_mem_cleanup(void)
250
{
250
{
251
  int i;
251
 int i;
252
  int count=0;
252
 int count=0;
253
  for (i = 0; i < MAX_MEM_DEBUG; i++)
253
 for (i = 0; i < MAX_MEM_DEBUG; i++)
254
    if (mem_debug[i].ptr != NULL) {
254
 if (mem_debug[i].ptr != NULL) {
255
      RDEBUG(0, "memdebug: failed to free memory allocated at line %d (%d b)",
255
 RDEBUG(0, "memdebug: failed to free memory allocated at line %d (%d b)",
256
	     mem_debug[i].line, mem_debug[i].size);
256
 mem_debug[i].line, mem_debug[i].size);
257
      count++;
257
 count++;
258
    }
258
 }
259
  if (!count)
259
 if (!count)
260
    RDEBUG(2, "congratulations - memory debugger is happy!");
260
 RDEBUG(2, "congratulations - memory debugger is happy!");
261
  kfree(mem_debug);
261
 kfree(mem_debug);
262
}
262
}
263
263
264
STATIC void fusd_mem_add(void *ptr, int line, int size)
264
STATIC void fusd_mem_add(void *ptr, int line, int size)
265
{
265
{
266
  int i;
266
 int i;
267
267
268
  if (ptr==NULL)
268
 if (ptr==NULL)
269
    return;
269
 return;
270
270
271
  for (i = 0; i < MAX_MEM_DEBUG; i++) {
271
 for (i = 0; i < MAX_MEM_DEBUG; i++) {
272
    if (mem_debug[i].ptr == NULL) {
272
 if (mem_debug[i].ptr == NULL) {
273
      mem_debug[i].ptr = ptr;
273
 mem_debug[i].ptr = ptr;
274
      mem_debug[i].line = line;
274
 mem_debug[i].line = line;
275
      mem_debug[i].size = size;
275
 mem_debug[i].size = size;
276
      return;
276
 return;
277
    }
277
 }
278
  }
278
 }
279
  RDEBUG(1, "WARNING - memdebug out of space!!!!");
279
 RDEBUG(1, "WARNING - memdebug out of space!!!!");
280
}
280
}
281
281
282
STATIC void fusd_mem_del(void *ptr)
282
STATIC void fusd_mem_del(void *ptr)
283
{
283
{
284
  int i;
284
 int i;
285
  for (i = 0; i < MAX_MEM_DEBUG; i++) {
285
 for (i = 0; i < MAX_MEM_DEBUG; i++) {
286
    if (mem_debug[i].ptr == ptr) {
286
 if (mem_debug[i].ptr == ptr) {
287
      mem_debug[i].ptr = NULL;
287
 mem_debug[i].ptr = NULL;
288
      return;
288
 return;
289
    }
289
 }
290
  }
290
 }
291
  RDEBUG(2, "WARNING - memdebug is confused!!!!");
291
 RDEBUG(2, "WARNING - memdebug is confused!!!!");
292
}
292
}
293
293
294
294
295
STATIC void *fusd_kmalloc(size_t size, int type, int line)
295
STATIC void *fusd_kmalloc(size_t size, int type, int line)
296
{
296
{
297
  void *ptr = kmalloc(size, type);
297
 void *ptr = kmalloc(size, type);
298
  down(&fusd_memdebug_sem);
298
 down(&fusd_memdebug_sem);
299
  fusd_mem_add(ptr, line, size);
299
 fusd_mem_add(ptr, line, size);
300
  up(&fusd_memdebug_sem);
300
 up(&fusd_memdebug_sem);
301
  return ptr;
301
 return ptr;
302
}
302
}
303
303
304
STATIC void fusd_kfree(void *ptr)
304
STATIC void fusd_kfree(void *ptr)
305
{
305
{
306
  down(&fusd_memdebug_sem);
306
 down(&fusd_memdebug_sem);
307
  fusd_mem_del(ptr);
307
 fusd_mem_del(ptr);
308
  kfree(ptr);
308
 kfree(ptr);
309
  up(&fusd_memdebug_sem);
309
 up(&fusd_memdebug_sem);
310
}
310
}
311
311
312
STATIC void *fusd_vmalloc(size_t size, int line)
312
STATIC void *fusd_vmalloc(size_t size, int line)
313
{
313
{
314
  void *ptr = vmalloc(size);
314
 void *ptr = vmalloc(size);
315
  down(&fusd_memdebug_sem);
315
 down(&fusd_memdebug_sem);
316
  fusd_mem_add(ptr, line, size);
316
 fusd_mem_add(ptr, line, size);
317
  up(&fusd_memdebug_sem);
317
 up(&fusd_memdebug_sem);
318
  return ptr;
318
 return ptr;
319
}
319
}
320
320
321
STATIC void fusd_vfree(void *ptr)
321
STATIC void fusd_vfree(void *ptr)
322
{
322
{
323
  down(&fusd_memdebug_sem);
323
 down(&fusd_memdebug_sem);
324
  fusd_mem_del(ptr);
324
 fusd_mem_del(ptr);
325
  vfree(ptr);
325
 vfree(ptr);
326
  up(&fusd_memdebug_sem);
326
 up(&fusd_memdebug_sem);
327
}
327
}
328
328
329
#endif /* CONFIG_FUSD_MEMDEBUG */
329
#endif /* CONFIG_FUSD_MEMDEBUG */
Lines 339-350 Link Here
339
339
340
STATIC inline void init_fusd_msg(fusd_msg_t *fusd_msg)
340
STATIC inline void init_fusd_msg(fusd_msg_t *fusd_msg)
341
{
341
{
342
  if (fusd_msg == NULL)
342
 if (fusd_msg == NULL)
343
    return;
343
 return;
344
344
345
  memset(fusd_msg, 0, sizeof(fusd_msg_t));
345
 memset(fusd_msg, 0, sizeof(fusd_msg_t));
346
  fusd_msg->magic = FUSD_MSG_MAGIC;
346
 fusd_msg->magic = FUSD_MSG_MAGIC;
347
  fusd_msg->cmd = FUSD_FOPS_CALL; /* typical, but can be overwritten */
347
 fusd_msg->cmd = FUSD_FOPS_CALL; /* typical, but can be overwritten */
348
}
348
}
349
349
350
/*
350
/*
Lines 352-503 Link Here
352
 */
352
 */
353
STATIC inline void free_fusd_msg(fusd_msg_t **fusd_msg)
353
STATIC inline void free_fusd_msg(fusd_msg_t **fusd_msg)
354
{
354
{
355
  if (fusd_msg == NULL || *fusd_msg == NULL)
355
 if (fusd_msg == NULL || *fusd_msg == NULL)
356
    return;
356
 return;
357
357
358
  if ((*fusd_msg)->data != NULL) {
358
 if ((*fusd_msg)->data != NULL) {
359
      VFREE((*fusd_msg)->data);
359
 VFREE((*fusd_msg)->data);
360
      (*fusd_msg)->data = NULL;
360
 (*fusd_msg)->data = NULL;
361
    }
361
 }
362
  KFREE(*fusd_msg);
362
 KFREE(*fusd_msg);
363
  *fusd_msg = NULL;
363
 *fusd_msg = NULL;
364
}
364
}
365
365
366
366
367
/* adjust the size of the 'files' array attached to the device to
367
/* adjust the size of the 'files' array attached to the device to
368
 * better match the number of files.  In all cases, size must be at
368
 * better match the number of files. In all cases, size must be at
369
 * least MIN_ARRAY_SIZE.  Subject to that constraint: if
369
 * least MIN_ARRAY_SIZE. Subject to that constraint: if
370
 * num_files==array_size, the size is doubled; if
370
 * num_files==array_size, the size is doubled; if
371
 * num_files<array_size/4, the size is halved.  Array is kept as is if
371
 * num_files<array_size/4, the size is halved. Array is kept as is if
372
 * the malloc fails.  Returns a pointer to the new file struct or NULL
372
 * the malloc fails. Returns a pointer to the new file struct or NULL
373
 * if there isn't one. */
373
 * if there isn't one. */
374
STATIC fusd_file_t **fusd_dev_adjsize(fusd_dev_t *fusd_dev)
374
STATIC fusd_file_t **fusd_dev_adjsize(fusd_dev_t *fusd_dev)
375
{
375
{
376
  fusd_file_t **old_array;
376
 fusd_file_t **old_array;
377
  int old_size;
377
 int old_size;
378
378
379
  old_array = fusd_dev->files;
379
 old_array = fusd_dev->files;
380
  old_size = fusd_dev->array_size;
380
 old_size = fusd_dev->array_size;
381
381
382
  /* compute the new size of the array */
382
 /* compute the new size of the array */
383
  if (fusd_dev->array_size > 4*fusd_dev->num_files)
383
 if (fusd_dev->array_size > 4*fusd_dev->num_files)
384
    fusd_dev->array_size /= 2;
384
 fusd_dev->array_size /= 2;
385
  else if (fusd_dev->array_size == fusd_dev->num_files)
385
 else if (fusd_dev->array_size == fusd_dev->num_files)
386
    fusd_dev->array_size *= 2;
386
 fusd_dev->array_size *= 2;
387
387
388
  /* respect the minimums and maximums (policy) */
388
 /* respect the minimums and maximums (policy) */
389
  if (fusd_dev->array_size < MIN_FILEARRAY_SIZE)
389
 if (fusd_dev->array_size < MIN_FILEARRAY_SIZE)
390
    fusd_dev->array_size = MIN_FILEARRAY_SIZE;
390
 fusd_dev->array_size = MIN_FILEARRAY_SIZE;
391
  if (fusd_dev->array_size > MAX_FILEARRAY_SIZE)
391
 if (fusd_dev->array_size > MAX_FILEARRAY_SIZE)
392
    fusd_dev->array_size = MAX_FILEARRAY_SIZE;
392
 fusd_dev->array_size = MAX_FILEARRAY_SIZE;
393
393
394
  /* make sure it's sane */
394
 /* make sure it's sane */
395
  if (fusd_dev->array_size < fusd_dev->num_files) {
395
 if (fusd_dev->array_size < fusd_dev->num_files) {
396
    RDEBUG(0, "fusd_dev_adjsize is royally screwed up!!!!!");
396
 RDEBUG(0, "fusd_dev_adjsize is royally screwed up!!!!!");
397
    return fusd_dev->files;
397
 return fusd_dev->files;
398
  }
398
 }
399
399
400
  /* create a new array.  if successful, copy the contents of the old
400
 /* create a new array. if successful, copy the contents of the old
401
   * one.  if not, revert back to the old. */
401
 * one. if not, revert back to the old. */
402
  fusd_dev->files = KMALLOC(fusd_dev->array_size * sizeof(fusd_file_t *),
402
 fusd_dev->files = KMALLOC(fusd_dev->array_size * sizeof(fusd_file_t *),
403
			    GFP_KERNEL);
403
 GFP_KERNEL);
404
  if (fusd_dev->files == NULL) {
404
 if (fusd_dev->files == NULL) {
405
    RDEBUG(1, "malloc failed in fusd_dev_adjsize!");
405
 RDEBUG(1, "malloc failed in fusd_dev_adjsize!");
406
    fusd_dev->files = old_array;
406
 fusd_dev->files = old_array;
407
    fusd_dev->array_size = old_size;
407
 fusd_dev->array_size = old_size;
408
  } else {
408
 } else {
409
    RDEBUG(10, "/dev/%s now has space for %d files (had %d)", NAME(fusd_dev),
409
 RDEBUG(10, "/dev/%s now has space for %d files (had %d)", NAME(fusd_dev),
410
	   fusd_dev->array_size, old_size);
410
 fusd_dev->array_size, old_size);
411
    memset(fusd_dev->files, 0, fusd_dev->array_size * sizeof(fusd_file_t *));
411
 memset(fusd_dev->files, 0, fusd_dev->array_size * sizeof(fusd_file_t *));
412
    memcpy(fusd_dev->files, old_array,
412
 memcpy(fusd_dev->files, old_array,
413
	   fusd_dev->num_files * sizeof(fusd_file_t *));
413
 fusd_dev->num_files * sizeof(fusd_file_t *));
414
    KFREE(old_array);
414
 KFREE(old_array);
415
  }
415
 }
416
416
417
  return fusd_dev->files;
417
 return fusd_dev->files;
418
}
418
}
419
419
420
420
421
/*
421
/*
422
 * DEVICE LOCK MUST BE HELD TO CALL THIS FUNCTION
422
 * DEVICE LOCK MUST BE HELD TO CALL THIS FUNCTION
423
 * 
423
 *
424
 * This function frees a device IF there is nothing left that is
424
 * This function frees a device IF there is nothing left that is
425
 * referencing it.
425
 * referencing it.
426
 *
426
 *
427
 * Specifically, we do not free the device if:
427
 * Specifically, we do not free the device if:
428
 *   - The driver is still active (i.e. device is not a zombie)
428
 * - The driver is still active (i.e. device is not a zombie)
429
 *   - There are still files with the device open
429
 * - There are still files with the device open
430
 *   - There is an open in progress, i.e. a client has verified that
430
 * - There is an open in progress, i.e. a client has verified that
431
 *   this is a valid device and is getting ready to add itself as an
431
 * this is a valid device and is getting ready to add itself as an
432
 *   open file.
432
 * open file.
433
 *
433
 *
434
 * If the device is safe to free, it is removed from the valid list
434
 * If the device is safe to free, it is removed from the valid list
435
 * (in verysafe mode only) and freed.
435
 * (in verysafe mode only) and freed.
436
 *
436
 *
437
 * Returns:  1 if the device was freed
437
 * Returns: 1 if the device was freed
438
 *           0 if the device still exists (and can be unlocked) */
438
 * 0 if the device still exists (and can be unlocked) */
439
STATIC int maybe_free_fusd_dev(fusd_dev_t *fusd_dev)
439
STATIC int maybe_free_fusd_dev(fusd_dev_t *fusd_dev)
440
{
440
{
441
  fusd_msgC_t *ptr, *next;
441
 fusd_msgC_t *ptr, *next;
442
442
443
  down(&fusd_devlist_sem);
443
 down(&fusd_devlist_sem);
444
444
445
  /* DON'T free the device under conditions listed above */
445
 /* DON'T free the device under conditions listed above */
446
  if (!fusd_dev->zombie || fusd_dev->num_files || fusd_dev->open_in_progress) {
446
 if (!fusd_dev->zombie || fusd_dev->num_files || fusd_dev->open_in_progress) {
447
    up(&fusd_devlist_sem);
447
 up(&fusd_devlist_sem);
448
    return 0;
448
 return 0;
449
  }
449
 }
450
450
451
  /* OK - bombs away!  This fusd_dev_t is on its way out the door! */
451
 /* OK - bombs away! This fusd_dev_t is on its way out the door! */
452
452
453
  RDEBUG(8, "freeing state associated with /dev/%s", NAME(fusd_dev));
453
 RDEBUG(8, "freeing state associated with /dev/%s", NAME(fusd_dev));
454
454
455
  /* delete it off the list of valid devices, and unlock */
455
 /* delete it off the list of valid devices, and unlock */
456
  list_del(&fusd_dev->devlist);
456
 list_del(&fusd_dev->devlist);
457
  up(&fusd_devlist_sem);
457
 up(&fusd_devlist_sem);
458
458
459
  /* free any outgoing messages that the device might have waiting */
459
 /* free any outgoing messages that the device might have waiting */
460
  for (ptr = fusd_dev->msg_head; ptr != NULL; ptr = next) {
460
 for (ptr = fusd_dev->msg_head; ptr != NULL; ptr = next) {
461
    next = ptr->next;
461
 next = ptr->next;
462
    FREE_FUSD_MSGC(ptr);
462
 FREE_FUSD_MSGC(ptr);
463
  }
463
 }
464
  
464
465
     /* free the device's dev name */
465
 /* free the device's dev name */
466
  if (fusd_dev->dev_name != NULL) {
466
 if (fusd_dev->dev_name != NULL) {
467
    KFREE(fusd_dev->dev_name);
467
 KFREE(fusd_dev->dev_name);
468
    fusd_dev->dev_name = NULL;
468
 fusd_dev->dev_name = NULL;
469
  }
469
 }
470
  
470
471
    /* free the device's class name */
471
 /* free the device's class name */
472
  if (fusd_dev->class_name != NULL) {
472
 if (fusd_dev->class_name != NULL) {
473
    KFREE(fusd_dev->class_name);
473
 KFREE(fusd_dev->class_name);
474
    fusd_dev->class_name = NULL;
474
 fusd_dev->class_name = NULL;
475
  }
475
 }
476
476
477
  /* free the device's name */
477
 /* free the device's name */
478
  if (fusd_dev->name != NULL) {
478
 if (fusd_dev->name != NULL) {
479
    KFREE(fusd_dev->name);
479
 KFREE(fusd_dev->name);
480
    fusd_dev->name = NULL;
480
 fusd_dev->name = NULL;
481
  }
481
 }
482
  
482
483
483
484
  /* free the array used to store pointers to fusd_file_t's */
484
 /* free the array used to store pointers to fusd_file_t's */
485
  if (fusd_dev->files != NULL) {
485
 if (fusd_dev->files != NULL) {
486
    KFREE(fusd_dev->files);
486
 KFREE(fusd_dev->files);
487
    fusd_dev->files = NULL;
487
 fusd_dev->files = NULL;
488
  }
488
 }
489
489
490
  /* clear the structure and free it! */
490
 /* clear the structure and free it! */
491
  memset(fusd_dev, 0, sizeof(fusd_dev_t));
491
 memset(fusd_dev, 0, sizeof(fusd_dev_t));
492
  KFREE(fusd_dev);
492
 KFREE(fusd_dev);
493
493
494
  /* notify fusd_status readers that there has been a change in the
494
 /* notify fusd_status readers that there has been a change in the
495
   * list of registered devices */
495
 * list of registered devices */
496
  atomic_inc_and_ret(&last_version);
496
 atomic_inc_and_ret(&last_version);
497
  wake_up_interruptible(&new_device_wait);
497
 wake_up_interruptible(&new_device_wait);
498
498
499
  //MOD_DEC_USE_COUNT;
499
 //MOD_DEC_USE_COUNT;
500
  return 1;
500
 return 1;
501
}
501
}
502
502
503
503
Lines 505-607 Link Here
505
 *
505
 *
506
 * DO NOT CALL THIS FUNCTION UNLESS THE DEVICE IS ALREADY LOCKED
506
 * DO NOT CALL THIS FUNCTION UNLESS THE DEVICE IS ALREADY LOCKED
507
 *
507
 *
508
 * zombify_device: called when the driver disappears.  Indicates that
508
 * zombify_device: called when the driver disappears. Indicates that
509
 * the driver is no longer available to service requests.  If there
509
 * the driver is no longer available to service requests. If there
510
 * are no outstanding system calls waiting for the fusd_dev state, the
510
 * are no outstanding system calls waiting for the fusd_dev state, the
511
 * device state itself is freed.
511
 * device state itself is freed.
512
 *
512
 *
513
 */
513
 */
514
STATIC void zombify_dev(fusd_dev_t *fusd_dev)
514
STATIC void zombify_dev(fusd_dev_t *fusd_dev)
515
{
515
{
516
  int i;
516
 int i;
517
517
518
  if (fusd_dev->zombie) {
518
 if (fusd_dev->zombie) {
519
    RDEBUG(1, "zombify_device called on a zombie!!");
519
 RDEBUG(1, "zombify_device called on a zombie!!");
520
    return;
520
 return;
521
  }
521
 }
522
522
523
  fusd_dev->zombie = 1;
523
 fusd_dev->zombie = 1;
524
524
525
  RDEBUG(3, "/dev/%s turning into a zombie (%d open files)", NAME(fusd_dev),
525
 RDEBUG(3, "/dev/%s turning into a zombie (%d open files)", NAME(fusd_dev),
526
	 fusd_dev->num_files);
526
 fusd_dev->num_files);
527
527
528
  /* If there are files holding this device open, wake them up. */
528
 /* If there are files holding this device open, wake them up. */
529
  for (i = 0; i < fusd_dev->num_files; i++) {
529
 for (i = 0; i < fusd_dev->num_files; i++) {
530
    wake_up_interruptible(&fusd_dev->files[i]->file_wait);
530
 wake_up_interruptible(&fusd_dev->files[i]->file_wait);
531
    wake_up_interruptible(&fusd_dev->files[i]->poll_wait);
531
 wake_up_interruptible(&fusd_dev->files[i]->poll_wait);
532
  }
532
 }
533
}
533
}
534
534
535
535
536
536
537
/* utility function to find the index of a fusd_file in a fusd_dev.
537
/* utility function to find the index of a fusd_file in a fusd_dev.
538
 * returns index if found, -1 if not found.  ASSUMES WE HAVE A VALID
538
 * returns index if found, -1 if not found. ASSUMES WE HAVE A VALID
539
 * fusd_dev.  fusd_file may be NULL if we are searching for an empty
539
 * fusd_dev. fusd_file may be NULL if we are searching for an empty
540
 * slot. */
540
 * slot. */
541
STATIC int find_fusd_file(fusd_dev_t *fusd_dev, fusd_file_t *fusd_file)
541
STATIC int find_fusd_file(fusd_dev_t *fusd_dev, fusd_file_t *fusd_file)
542
{
542
{
543
  int i, num_files = fusd_dev->num_files;
543
 int i, num_files = fusd_dev->num_files;
544
  fusd_file_t **files = fusd_dev->files;
544
 fusd_file_t **files = fusd_dev->files;
545
545
546
  for (i = 0; i < num_files; i++)
546
 for (i = 0; i < num_files; i++)
547
    if (files[i] == fusd_file)
547
 if (files[i] == fusd_file)
548
      return i;
548
 return i;
549
549
550
  return -1;
550
 return -1;
551
}
551
}
552
552
553
553
554
/*
554
/*
555
 * DEVICE LOCK MUST BE HELD BEFORE THIS IS CALLED
555
 * DEVICE LOCK MUST BE HELD BEFORE THIS IS CALLED
556
 *
556
 *
557
 * Returns 1 if the device was also freed.  0 if only the file was
557
 * Returns 1 if the device was also freed. 0 if only the file was
558
 * freed.  If the device is freed, then do not try to unlock it!
558
 * freed. If the device is freed, then do not try to unlock it!
559
 * (Callers: Check the return value before unlocking!)
559
 * (Callers: Check the return value before unlocking!)
560
 */
560
 */
561
STATIC int free_fusd_file(fusd_dev_t *fusd_dev, fusd_file_t *fusd_file)
561
STATIC int free_fusd_file(fusd_dev_t *fusd_dev, fusd_file_t *fusd_file)
562
{
562
{
563
  int i;
563
 int i;
564
  struct list_head *tmp, *it;
564
 struct list_head *tmp, *it;
565
   
566
  /* find the index of the file in the device's file-list... */
567
  if ((i = find_fusd_file(fusd_dev, fusd_file)) < 0)
568
    panic("corrupted fusd_dev: releasing a file that we think is closed");
569
    
570
  /* ...and remove it (by putting the last entry into its place) */
571
  fusd_dev->files[i] = fusd_dev->files[--(fusd_dev->num_files)];
572
573
  /* there might be an incoming message waiting for a restarted system
574
   * call.  free it -- after possibly forging a close (see
575
   * fusd_forge_close). */
576
   
577
   
578
	list_for_each_safe(it, tmp, &fusd_file->transactions)
579
	{
580
		struct fusd_transaction* transaction = list_entry(it, struct fusd_transaction, list);
581
		if(transaction->msg_in)
582
		{
583
      if (transaction->msg_in->subcmd == FUSD_OPEN && transaction->msg_in->parm.fops_msg.retval == 0)
584
        fusd_forge_close(transaction->msg_in, fusd_dev);
585
      free_fusd_msg(&transaction->msg_in);
586
		} 
587
		KFREE(transaction);
588
	}
589
  
590
  /* free state associated with this file */
591
  memset(fusd_file, 0, sizeof(fusd_file_t));
592
  KFREE(fusd_file);
593
594
  /* reduce the size of the file array if necessary */
595
  if (fusd_dev->array_size > MIN_FILEARRAY_SIZE &&
596
      fusd_dev->array_size > 4*fusd_dev->num_files)
597
    fusd_dev_adjsize(fusd_dev);
598
599
  /* renumber the array */
600
  for (i = 0; i < fusd_dev->num_files; i++)
601
    fusd_dev->files[i]->index = i;
602
565
603
  /* try to free the device -- this may have been its last file */
566
 /* find the index of the file in the device's file-list... */
604
  return maybe_free_fusd_dev(fusd_dev);
567
 if ((i = find_fusd_file(fusd_dev, fusd_file)) < 0)
568
 panic("corrupted fusd_dev: releasing a file that we think is closed");
569
570
 /* ...and remove it (by putting the last entry into its place) */
571
 fusd_dev->files[i] = fusd_dev->files[--(fusd_dev->num_files)];
572
573
 /* there might be an incoming message waiting for a restarted system
574
 * call. free it -- after possibly forging a close (see
575
 * fusd_forge_close). */
576
577
578
 list_for_each_safe(it, tmp, &fusd_file->transactions)
579
 {
580
 struct fusd_transaction* transaction = list_entry(it, struct fusd_transaction, list);
581
 if(transaction->msg_in)
582
 {
583
 if (transaction->msg_in->subcmd == FUSD_OPEN && transaction->msg_in->parm.fops_msg.retval == 0)
584
 fusd_forge_close(transaction->msg_in, fusd_dev);
585
 free_fusd_msg(&transaction->msg_in);
586
 }
587
 KFREE(transaction);
588
 }
589
590
 /* free state associated with this file */
591
 memset(fusd_file, 0, sizeof(fusd_file_t));
592
 KFREE(fusd_file);
593
594
 /* reduce the size of the file array if necessary */
595
 if (fusd_dev->array_size > MIN_FILEARRAY_SIZE &&
596
 fusd_dev->array_size > 4*fusd_dev->num_files)
597
 fusd_dev_adjsize(fusd_dev);
598
599
 /* renumber the array */
600
 for (i = 0; i < fusd_dev->num_files; i++)
601
 fusd_dev->files[i]->index = i;
602
603
 /* try to free the device -- this may have been its last file */
604
 return maybe_free_fusd_dev(fusd_dev);
605
}
605
}
606
606
607
607
Lines 622-703 Link Here
622
 *
622
 *
623
 * In the even LESS (hopefully very rare) case when one PID had an
623
 * In the even LESS (hopefully very rare) case when one PID had an
624
 * interrupted syscall, but a different PID is the next to do a system
624
 * interrupted syscall, but a different PID is the next to do a system
625
 * call on that file descriptor -- well, we lose.  Clear state of that
625
 * call on that file descriptor -- well, we lose. Clear state of that
626
 * old syscall out and continue as usual.
626
 * old syscall out and continue as usual.
627
 */
627
 */
628
STATIC struct fusd_transaction* fusd_find_incomplete_transaction(fusd_file_t *fusd_file, int subcmd)
628
STATIC struct fusd_transaction* fusd_find_incomplete_transaction(fusd_file_t *fusd_file, int subcmd)
629
{
629
{
630
  struct fusd_transaction* transaction = fusd_find_transaction_by_pid(fusd_file, current->pid);
630
 struct fusd_transaction* transaction = fusd_find_transaction_by_pid(fusd_file, current->pid);
631
  if(transaction == NULL)
631
 if(transaction == NULL)
632
    return NULL;
632
 return NULL;
633
633
634
634
635
  if (transaction->subcmd != subcmd)
635
 if (transaction->subcmd != subcmd)
636
  {
636
 {
637
    RDEBUG(2, "Incomplete transaction %ld thrown out, was expecting subcmd %d but received %d", 
637
 RDEBUG(2, "Incomplete transaction %ld thrown out, was expecting subcmd %d but received %d",
638
           transaction->transid, transaction->subcmd, subcmd);
638
 transaction->transid, transaction->subcmd, subcmd);
639
    fusd_cleanup_transaction(fusd_file, transaction);
639
 fusd_cleanup_transaction(fusd_file, transaction);
640
    return NULL;
640
 return NULL;
641
  }
641
 }
642
  
642
643
  RDEBUG(4, "pid %d restarting system call with transid %ld", current->pid,
643
 RDEBUG(4, "pid %d restarting system call with transid %ld", current->pid,
644
         transaction->transid);
644
 transaction->transid);
645
  return transaction;
645
 return transaction;
646
}
646
}
647
647
648
648
649
STATIC int send_to_dev(fusd_dev_t *fusd_dev, fusd_msg_t *fusd_msg, int locked)
649
STATIC int send_to_dev(fusd_dev_t *fusd_dev, fusd_msg_t *fusd_msg, int locked)
650
{
650
{
651
  fusd_msgC_t *fusd_msgC;
651
 fusd_msgC_t *fusd_msgC;
652
652
653
  /* allocate a container for the message */
653
 /* allocate a container for the message */
654
  if ((fusd_msgC = KMALLOC(sizeof(fusd_msgC_t), GFP_KERNEL)) == NULL)
654
 if ((fusd_msgC = KMALLOC(sizeof(fusd_msgC_t), GFP_KERNEL)) == NULL)
655
    return -ENOMEM;
655
 return -ENOMEM;
656
656
657
  memset(fusd_msgC, 0, sizeof(fusd_msgC_t));
657
 memset(fusd_msgC, 0, sizeof(fusd_msgC_t));
658
  memcpy(&fusd_msgC->fusd_msg, fusd_msg, sizeof(fusd_msg_t));
658
 memcpy(&fusd_msgC->fusd_msg, fusd_msg, sizeof(fusd_msg_t));
659
659
660
  if (!locked)
660
 if (!locked)
661
    LOCK_FUSD_DEV(fusd_dev);
661
 LOCK_FUSD_DEV(fusd_dev);
662
662
663
  /* put the message in the device's outgoing queue.  */
663
 /* put the message in the device's outgoing queue. */
664
  if (fusd_dev->msg_head == NULL) {
664
 if (fusd_dev->msg_head == NULL) {
665
    fusd_dev->msg_head = fusd_dev->msg_tail = fusd_msgC;
665
 fusd_dev->msg_head = fusd_dev->msg_tail = fusd_msgC;
666
  } else {
666
 } else {
667
    fusd_dev->msg_tail->next = fusd_msgC;
667
 fusd_dev->msg_tail->next = fusd_msgC;
668
    fusd_dev->msg_tail = fusd_msgC;
668
 fusd_dev->msg_tail = fusd_msgC;
669
  }
669
 }
670
670
671
  if (!locked)
671
 if (!locked)
672
    UNLOCK_FUSD_DEV(fusd_dev);
672
 UNLOCK_FUSD_DEV(fusd_dev);
673
673
674
  /* wake up the driver, which now has a message waiting in its queue */
674
 /* wake up the driver, which now has a message waiting in its queue */
675
  WAKE_UP_INTERRUPTIBLE_SYNC(&fusd_dev->dev_wait);
675
 WAKE_UP_INTERRUPTIBLE_SYNC(&fusd_dev->dev_wait);
676
676
677
  return 0;
677
 return 0;
678
678
679
 zombie_dev:
679
 zombie_dev:
680
  KFREE(fusd_msgC);
680
 KFREE(fusd_msgC);
681
  return -EPIPE;
681
 return -EPIPE;
682
}
682
}
683
683
684
684
685
/* 
685
/*
686
 * special case: if the driver sent back a successful "open", but
686
 * special case: if the driver sent back a successful "open", but
687
 * there is no file that is actually open, we forge a "close" so that
687
 * there is no file that is actually open, we forge a "close" so that
688
 * the driver can maintain balanced open/close pairs.  We put calls to
688
 * the driver can maintain balanced open/close pairs. We put calls to
689
 * this in fusd_fops_reply, when the reply first comes in; and,
689
 * this in fusd_fops_reply, when the reply first comes in; and,
690
 * free_fusd_file, when we throw away a reply that had been
690
 * free_fusd_file, when we throw away a reply that had been
691
 * pending for a restart.
691
 * pending for a restart.
692
 */
692
 */
693
STATIC void fusd_forge_close(fusd_msg_t *msg, fusd_dev_t *fusd_dev)
693
STATIC void fusd_forge_close(fusd_msg_t *msg, fusd_dev_t *fusd_dev)
694
{
694
{
695
  RDEBUG(2, "/dev/%s tried to complete an open for transid %ld, "
695
 RDEBUG(2, "/dev/%s tried to complete an open for transid %ld, "
696
	 "forging a close", NAME(fusd_dev), msg->parm.fops_msg.transid);
696
 "forging a close", NAME(fusd_dev), msg->parm.fops_msg.transid);
697
  msg->cmd = FUSD_FOPS_CALL_DROPREPLY;
697
 msg->cmd = FUSD_FOPS_CALL_DROPREPLY;
698
  msg->subcmd = FUSD_CLOSE;
698
 msg->subcmd = FUSD_CLOSE;
699
  msg->parm.fops_msg.transid = atomic_inc_and_ret(&last_transid);
699
 msg->parm.fops_msg.transid = atomic_inc_and_ret(&last_transid);
700
  send_to_dev(fusd_dev, msg, 1);
700
 send_to_dev(fusd_dev, msg, 1);
701
}
701
}
702
702
703
703
Lines 709-778 Link Here
709
 * function is called, but NOT the lock on the fusd_dev
709
 * function is called, but NOT the lock on the fusd_dev
710
 */
710
 */
711
STATIC int fusd_fops_call_send(fusd_file_t *fusd_file_arg,
711
STATIC int fusd_fops_call_send(fusd_file_t *fusd_file_arg,
712
			       fusd_msg_t *fusd_msg, struct fusd_transaction** transaction)
712
 fusd_msg_t *fusd_msg, struct fusd_transaction** transaction)
713
{
713
{
714
  fusd_dev_t *fusd_dev;
714
 fusd_dev_t *fusd_dev;
715
  fusd_file_t *fusd_file;
715
 fusd_file_t *fusd_file;
716
717
 /* I check this just in case, shouldn't be necessary. */
718
 GET_FUSD_FILE_AND_DEV(fusd_file_arg, fusd_file, fusd_dev);
716
719
717
  /* I check this just in case, shouldn't be necessary. */
720
 /* make sure message is sane */
718
  GET_FUSD_FILE_AND_DEV(fusd_file_arg, fusd_file, fusd_dev);
721
 if ((fusd_msg->data == NULL) != (fusd_msg->datalen == 0)) {
722
 RDEBUG(2, "fusd_fops_call: data pointer and datalen mismatch");
723
 return -EINVAL;
724
 }
725
726
 /* fill the rest of the structure */
727
 fusd_msg->parm.fops_msg.pid = current->pid;
728
 fusd_msg->parm.fops_msg.uid = current->uid;
729
 fusd_msg->parm.fops_msg.gid = current->gid;
730
 fusd_msg->parm.fops_msg.flags = fusd_file->file->f_flags;
731
 fusd_msg->parm.fops_msg.offset = fusd_file->file->f_pos;
732
 fusd_msg->parm.fops_msg.device_info = fusd_dev->private_data;
733
 fusd_msg->parm.fops_msg.private_info = fusd_file->private_data;
734
 fusd_msg->parm.fops_msg.fusd_file = fusd_file;
735
 fusd_msg->parm.fops_msg.transid = atomic_inc_and_ret(&last_transid);
736
737
 /* set up certain state depending on if we expect a reply */
738
 switch (fusd_msg->cmd) {
739
740
 case FUSD_FOPS_CALL: /* common case */
741
 fusd_msg->parm.fops_msg.hint = fusd_file->index;
742
743
 break;
744
745
 case FUSD_FOPS_CALL_DROPREPLY:
746
 /* nothing needed */
747
 break;
748
749
 case FUSD_FOPS_NONBLOCK:
750
 fusd_msg->parm.fops_msg.hint = fusd_file->index;
751
 break;
752
753
 default:
754
 RDEBUG(0, "whoa - fusd_fops_call_send got msg with unknown cmd!");
755
 break;
756
 }
757
758
 if(transaction != NULL)
759
 {
760
 int retval;
761
 retval = fusd_add_transaction(fusd_file, fusd_msg->parm.fops_msg.transid, fusd_msg->subcmd,
762
 fusd_msg->parm.fops_msg.length, transaction);
763
 if(retval < 0)
764
 return retval;
765
 }
719
766
720
  /* make sure message is sane */
767
 /* now add the message to the device's outgoing queue! */
721
  if ((fusd_msg->data == NULL) != (fusd_msg->datalen == 0)) {
768
 return send_to_dev(fusd_dev, fusd_msg, 0);
722
    RDEBUG(2, "fusd_fops_call: data pointer and datalen mismatch");
723
    return -EINVAL;
724
  }
725
726
  /* fill the rest of the structure */
727
  fusd_msg->parm.fops_msg.pid = current->pid;
728
  fusd_msg->parm.fops_msg.uid = current->uid;
729
  fusd_msg->parm.fops_msg.gid = current->gid;
730
  fusd_msg->parm.fops_msg.flags = fusd_file->file->f_flags;
731
  fusd_msg->parm.fops_msg.offset = fusd_file->file->f_pos;
732
  fusd_msg->parm.fops_msg.device_info = fusd_dev->private_data;
733
  fusd_msg->parm.fops_msg.private_info = fusd_file->private_data;
734
  fusd_msg->parm.fops_msg.fusd_file = fusd_file;
735
  fusd_msg->parm.fops_msg.transid = atomic_inc_and_ret(&last_transid);
736
737
  /* set up certain state depending on if we expect a reply */
738
  switch (fusd_msg->cmd) {
739
740
  case FUSD_FOPS_CALL: /* common case */
741
    fusd_msg->parm.fops_msg.hint = fusd_file->index;
742
     
743
    break;
744
745
  case FUSD_FOPS_CALL_DROPREPLY:
746
    /* nothing needed */
747
    break;
748
749
  case FUSD_FOPS_NONBLOCK:
750
    fusd_msg->parm.fops_msg.hint = fusd_file->index;
751
    break;
752
753
  default:
754
    RDEBUG(0, "whoa - fusd_fops_call_send got msg with unknown cmd!");
755
    break;
756
  }
757
  
758
  if(transaction != NULL)
759
  {
760
    int retval;
761
    retval = fusd_add_transaction(fusd_file, fusd_msg->parm.fops_msg.transid, fusd_msg->subcmd,
762
                    fusd_msg->parm.fops_msg.length, transaction);
763
    if(retval < 0)
764
      return retval;
765
  }
766
  
767
  /* now add the message to the device's outgoing queue! */
768
  return send_to_dev(fusd_dev, fusd_msg, 0);
769
769
770
770
771
  /* bizarre errors go straight here */
771
 /* bizarre errors go straight here */
772
 invalid_dev:
772
 invalid_dev:
773
 invalid_file:
773
 invalid_file:
774
  RDEBUG(0, "fusd_fops_call: got invalid device or file!!!!");
774
 RDEBUG(0, "fusd_fops_call: got invalid device or file!!!!");
775
  return -EPIPE;
775
 return -EPIPE;
776
}
776
}
777
777
778
778
Lines 783-891 Link Here
783
 * function is called, but NOT the lock on the fusd_dev
783
 * function is called, but NOT the lock on the fusd_dev
784
 */
784
 */
785
STATIC int fusd_fops_call_wait(fusd_file_t *fusd_file_arg,
785
STATIC int fusd_fops_call_wait(fusd_file_t *fusd_file_arg,
786
			       fusd_msg_t **fusd_msg_reply, struct fusd_transaction* transaction)
786
 fusd_msg_t **fusd_msg_reply, struct fusd_transaction* transaction)
787
{
787
{
788
  fusd_dev_t *fusd_dev;
788
 fusd_dev_t *fusd_dev;
789
  fusd_file_t *fusd_file;
789
 fusd_file_t *fusd_file;
790
  int retval;
790
 int retval;
791
791
792
  /* I check this just in case, shouldn't be necessary. */
792
 /* I check this just in case, shouldn't be necessary. */
793
  GET_FUSD_FILE_AND_DEV(fusd_file_arg, fusd_file, fusd_dev);
793
 GET_FUSD_FILE_AND_DEV(fusd_file_arg, fusd_file, fusd_dev);
794
794
795
  /* initialize first to tell callers there is no reply (yet) */
795
 /* initialize first to tell callers there is no reply (yet) */
796
  if (fusd_msg_reply != NULL)
796
 if (fusd_msg_reply != NULL)
797
    *fusd_msg_reply = NULL;
797
 *fusd_msg_reply = NULL;
798
798
799
  /*
799
 /*
800
   * Now, lock the device, check for an incoming message, and sleep if
800
 * Now, lock the device, check for an incoming message, and sleep if
801
   * there is not a message already waiting for us.  Note that we are
801
 * there is not a message already waiting for us. Note that we are
802
   * unrolling the interruptible_sleep_on, as in the kernel's
802
 * unrolling the interruptible_sleep_on, as in the kernel's
803
   * fs/pipe.c, to avoid race conditions between checking for the
803
 * fs/pipe.c, to avoid race conditions between checking for the
804
   * sleep condition and sleeping.
804
 * sleep condition and sleeping.
805
   */
805
 */
806
  LOCK_FUSD_DEV(fusd_dev);
806
 LOCK_FUSD_DEV(fusd_dev);
807
  while (transaction->msg_in == NULL) {
807
 while (transaction->msg_in == NULL) {
808
    DECLARE_WAITQUEUE(wait, current);
808
 DECLARE_WAITQUEUE(wait, current);
809
809
810
    RDEBUG(10, "pid %d blocking on transid %ld", current->pid, transaction->transid);
810
 RDEBUG(10, "pid %d blocking on transid %ld", current->pid, transaction->transid);
811
    current->state = TASK_INTERRUPTIBLE;
811
 current->state = TASK_INTERRUPTIBLE;
812
    add_wait_queue(&fusd_file->file_wait, &wait);
812
 add_wait_queue(&fusd_file->file_wait, &wait);
813
    UNLOCK_FUSD_DEV(fusd_dev);
813
 UNLOCK_FUSD_DEV(fusd_dev);
814
    UNLOCK_FUSD_FILE(fusd_file);
814
 UNLOCK_FUSD_FILE(fusd_file);
815
815
816
    schedule();
816
 schedule();
817
    remove_wait_queue(&fusd_file->file_wait, &wait);
817
 remove_wait_queue(&fusd_file->file_wait, &wait);
818
    current->state = TASK_RUNNING;
818
 current->state = TASK_RUNNING;
819
819
820
    /*
820
 /*
821
     * If we woke up due to a signal -- and not due to a reply message
821
 * If we woke up due to a signal -- and not due to a reply message
822
     * coming in -- then we are in some trouble.  The driver is already
822
 * coming in -- then we are in some trouble. The driver is already
823
     * processing the request and might have changed some state that is
823
 * processing the request and might have changed some state that is
824
     * hard to roll back.  So, we'll tell the process to restart the
824
 * hard to roll back. So, we'll tell the process to restart the
825
     * system call, and come back to this point when the system call is
825
 * system call, and come back to this point when the system call is
826
     * restarted.  We need to remember the PID to avoid confusion in
826
 * restarted. We need to remember the PID to avoid confusion in
827
     * case there is another process holding this file descriptor that
827
 * case there is another process holding this file descriptor that
828
     * is also trying to make a call.
828
 * is also trying to make a call.
829
     */
829
 */
830
    if (signal_pending(current)) {
830
 if (signal_pending(current)) {
831
      RDEBUG(5, "blocked pid %d got a signal; sending -ERESTARTSYS",
831
 RDEBUG(5, "blocked pid %d got a signal; sending -ERESTARTSYS",
832
	     current->pid);
832
 current->pid);
833
			LOCK_FUSD_FILE(fusd_file);
833
 LOCK_FUSD_FILE(fusd_file);
834
      return -ERESTARTSYS;
834
 return -ERESTARTSYS;
835
    }
835
 }
836
836
837
    LOCK_FUSD_FILE(fusd_file);
837
 LOCK_FUSD_FILE(fusd_file);
838
    /* re-lock the device, so we can do our msg_in check again */
838
 /* re-lock the device, so we can do our msg_in check again */
839
    LOCK_FUSD_DEV(fusd_dev);
839
 LOCK_FUSD_DEV(fusd_dev);
840
  }
840
 }
841
  UNLOCK_FUSD_DEV(fusd_dev);
841
 UNLOCK_FUSD_DEV(fusd_dev);
842
842
843
  /* ok - at this point we are awake due to a message received. */
843
 /* ok - at this point we are awake due to a message received. */
844
844
845
  if (transaction->msg_in->cmd != FUSD_FOPS_REPLY ||
845
 if (transaction->msg_in->cmd != FUSD_FOPS_REPLY ||
846
      transaction->msg_in->subcmd != transaction->subcmd ||
846
 transaction->msg_in->subcmd != transaction->subcmd ||
847
      transaction->msg_in->parm.fops_msg.transid != transaction->transid ||
847
 transaction->msg_in->parm.fops_msg.transid != transaction->transid ||
848
      transaction->msg_in->parm.fops_msg.fusd_file != fusd_file) {
848
 transaction->msg_in->parm.fops_msg.fusd_file != fusd_file) {
849
    RDEBUG(2, "fusd_fops_call: invalid reply!");
849
 RDEBUG(2, "fusd_fops_call: invalid reply!");
850
    goto invalid_reply;
850
 goto invalid_reply;
851
  }
851
 }
852
852
853
  /* copy metadata back from userspace */
853
 /* copy metadata back from userspace */
854
  fusd_file->file->f_flags = transaction->msg_in->parm.fops_msg.flags;
854
 fusd_file->file->f_flags = transaction->msg_in->parm.fops_msg.flags;
855
  fusd_file->private_data  = transaction->msg_in->parm.fops_msg.private_info;
855
 fusd_file->private_data = transaction->msg_in->parm.fops_msg.private_info;
856
  /* note, changes to device_info are NO LONGER honored here */
856
 /* note, changes to device_info are NO LONGER honored here */
857
857
858
  /* if everything's okay, return the return value.  if caller is
858
 /* if everything's okay, return the return value. if caller is
859
   * willing to take responsibility for freeing the message itself, we
859
 * willing to take responsibility for freeing the message itself, we
860
   * return the message too. */
860
 * return the message too. */
861
  retval = transaction->msg_in->parm.fops_msg.retval;
861
 retval = transaction->msg_in->parm.fops_msg.retval;
862
  if (fusd_msg_reply != NULL) {
862
 if (fusd_msg_reply != NULL) {
863
    /* NOW TRANSFERRING RESPONSIBILITY FOR FREEING THIS DATA TO THE CALLER */
863
 /* NOW TRANSFERRING RESPONSIBILITY FOR FREEING THIS DATA TO THE CALLER */
864
    *fusd_msg_reply = transaction->msg_in;
864
 *fusd_msg_reply = transaction->msg_in;
865
    transaction->msg_in = NULL;
865
 transaction->msg_in = NULL;
866
  } else {
866
 } else {
867
    /* free the message ourselves */
867
 /* free the message ourselves */
868
    free_fusd_msg(&transaction->msg_in);
868
 free_fusd_msg(&transaction->msg_in);
869
  }
869
 }
870
  
870
871
  /* success */
871
 /* success */
872
  fusd_cleanup_transaction(fusd_file, transaction);
872
 fusd_cleanup_transaction(fusd_file, transaction);
873
  return retval;
873
 return retval;
874
874
875
 invalid_reply:
875
 invalid_reply:
876
  fusd_cleanup_transaction(fusd_file, transaction);
876
 fusd_cleanup_transaction(fusd_file, transaction);
877
  return -EPIPE;
877
 return -EPIPE;
878
878
879
  /* bizarre errors go straight here */
879
 /* bizarre errors go straight here */
880
 invalid_dev:
880
 invalid_dev:
881
 invalid_file:
881
 invalid_file:
882
  RDEBUG(0, "fusd_fops_call: got invalid device or file!!!!");
882
 RDEBUG(0, "fusd_fops_call: got invalid device or file!!!!");
883
  return -EPIPE;
883
 return -EPIPE;
884
884
885
 zombie_dev:
885
 zombie_dev:
886
  RDEBUG(2, "fusd_fops_call: %s zombified while waiting for reply",
886
 RDEBUG(2, "fusd_fops_call: %s zombified while waiting for reply",
887
	 NAME(fusd_dev));
887
 NAME(fusd_dev));
888
  return -EPIPE;
888
 return -EPIPE;
889
}
889
}
890
890
891
891
Lines 893-900 Link Here
893
 * fops_call, to destroy the message that was returned to them. */
893
 * fops_call, to destroy the message that was returned to them. */
894
STATIC void fusd_transaction_done(struct fusd_transaction *transaction)
894
STATIC void fusd_transaction_done(struct fusd_transaction *transaction)
895
{
895
{
896
	transaction->transid = -1;
896
 transaction->transid = -1;
897
	transaction->pid = 0;
897
 transaction->pid = 0;
898
}
898
}
899
899
900
900
Lines 905-933 Link Here
905
/*
905
/*
906
 * The process of having a client open a FUSD device is surprisingly
906
 * The process of having a client open a FUSD device is surprisingly
907
 * tricky -- perhaps the most complex piece of FUSD (or, a close
907
 * tricky -- perhaps the most complex piece of FUSD (or, a close
908
 * second to poll_diffs).  Race conditions are rampant here.
908
 * second to poll_diffs). Race conditions are rampant here.
909
 *
909
 *
910
 * The main problem is that there is a race between clients trying to
910
 * The main problem is that there is a race between clients trying to
911
 * open the FUSD device, and providers unregistering it (e.g., the
911
 * open the FUSD device, and providers unregistering it (e.g., the
912
 * driver dying).  If the device-unregister callback starts, and is
912
 * driver dying). If the device-unregister callback starts, and is
913
 * scheduled out after it locks the fusd device but before it
913
 * scheduled out after it locks the fusd device but before it
914
 * unregisters the device with devfs, the open callback might be
914
 * unregisters the device with devfs, the open callback might be
915
 * invoked in this interval.  This means the client will down() on a
915
 * invoked in this interval. This means the client will down() on a
916
 * semaphore that is about to be freed when the device is destroyed.
916
 * semaphore that is about to be freed when the device is destroyed.
917
 *
917
 *
918
 * The only way to fix this, as far as I can tell, is for device
918
 * The only way to fix this, as far as I can tell, is for device
919
 * registration and unregistration to both share a global lock; the
919
 * registration and unregistration to both share a global lock; the
920
 * client checks its 'private_data' pointer to make sure it's on the
920
 * client checks its 'private_data' pointer to make sure it's on the
921
 * list of valid devices.  If so, it sets a flag (open_in_progress)
921
 * list of valid devices. If so, it sets a flag (open_in_progress)
922
 * which means "Don't free this device yet!".  Then, it releases the
922
 * which means "Don't free this device yet!". Then, it releases the
923
 * global lock, grabs the device lock, and tries to add itself as a
923
 * global lock, grabs the device lock, and tries to add itself as a
924
 * "file" to the device array.  It is then safe to decrement
924
 * "file" to the device array. It is then safe to decrement
925
 * open_in_progress, because being a member of the file array will
925
 * open_in_progress, because being a member of the file array will
926
 * guarantee that the device will zombify instead of being freed.
926
 * guarantee that the device will zombify instead of being freed.
927
 *
927
 *
928
 * Another gotcha: To avoid infinitely dining with philosophers, the
928
 * Another gotcha: To avoid infinitely dining with philosophers, the
929
 * global lock (fusd_devlist_sem) should always be acquired AFTER a
929
 * global lock (fusd_devlist_sem) should always be acquired AFTER a
930
 * fusd device is locked.  The code path that frees devices acquires
930
 * fusd device is locked. The code path that frees devices acquires
931
 * the device lock FIRST, so the code here must do the same.
931
 * the device lock FIRST, so the code here must do the same.
932
 *
932
 *
933
 * Because of the complexity of opening a file, I've broken it up into
933
 * Because of the complexity of opening a file, I've broken it up into
Lines 941-1054 Link Here
941
 */
941
 */
942
int fusd_dev_is_valid(fusd_dev_t *fusd_dev)
942
int fusd_dev_is_valid(fusd_dev_t *fusd_dev)
943
{
943
{
944
  struct list_head *tmp;
944
 struct list_head *tmp;
945
  int dev_found = 0;
945
 int dev_found = 0;
946
946
947
  /* The first thing we must do is acquire the global lock on the
947
 /* The first thing we must do is acquire the global lock on the
948
   * device list, and make sure this device is valid; if so, mark it
948
 * device list, and make sure this device is valid; if so, mark it
949
   * as being "in use".  If we don't do this, there's a race: after we
949
 * as being "in use". If we don't do this, there's a race: after we
950
   * enter this function, the device may be unregistered. */
950
 * enter this function, the device may be unregistered. */
951
  down(&fusd_devlist_sem);
951
 down(&fusd_devlist_sem);
952
  list_for_each(tmp, &fusd_devlist_head) {
952
 list_for_each(tmp, &fusd_devlist_head) {
953
    fusd_dev_t *d = list_entry(tmp, fusd_dev_t, devlist);
953
 fusd_dev_t *d = list_entry(tmp, fusd_dev_t, devlist);
954
954
955
    if (d == fusd_dev && d->magic == FUSD_DEV_MAGIC && !ZOMBIE(d)) {
955
 if (d == fusd_dev && d->magic == FUSD_DEV_MAGIC && !ZOMBIE(d)) {
956
      dev_found = 1;
956
 dev_found = 1;
957
      break;
957
 break;
958
    }
958
 }
959
  }
959
 }
960
960
961
  /* A device will not be deallocated when this counter is >0 */
961
 /* A device will not be deallocated when this counter is >0 */
962
  if (dev_found)
962
 if (dev_found)
963
    fusd_dev->open_in_progress++;
963
 fusd_dev->open_in_progress++;
964
964
965
  up(&fusd_devlist_sem);
965
 up(&fusd_devlist_sem);
966
966
967
  return dev_found;
967
 return dev_found;
968
}
968
}
969
969
970
970
971
int fusd_dev_add_file(struct file *file, fusd_dev_t *fusd_dev, fusd_file_t **fusd_file_ret)
971
int fusd_dev_add_file(struct file *file, fusd_dev_t *fusd_dev, fusd_file_t **fusd_file_ret)
972
{
972
{
973
  fusd_file_t *fusd_file;
973
 fusd_file_t *fusd_file;
974
  int i;
974
 int i;
975
975
976
  /* Make sure the device didn't become a zombie while we were waiting
976
 /* Make sure the device didn't become a zombie while we were waiting
977
   * for the device lock */
977
 * for the device lock */
978
  if (ZOMBIE(fusd_dev))
978
 if (ZOMBIE(fusd_dev))
979
    return -ENOENT;
979
 return -ENOENT;
980
980
981
  /* this shouldn't happen.  maybe i'm insane, but i check anyway. */
981
 /* this shouldn't happen. maybe i'm insane, but i check anyway. */
982
  for (i = 0; i < fusd_dev->num_files; i++)
982
 for (i = 0; i < fusd_dev->num_files; i++)
983
    if (fusd_dev->files[i]->file == file) {
983
 if (fusd_dev->files[i]->file == file) {
984
      RDEBUG(1, "warning: fusd_client_open got open for already-open file!?");
984
 RDEBUG(1, "warning: fusd_client_open got open for already-open file!?");
985
      return -EIO;
985
 return -EIO;
986
    }
986
 }
987
987
988
  /* You can't open your own file!  Return -EDEADLOCK if someone tries to.
988
 /* You can't open your own file! Return -EDEADLOCK if someone tries to.
989
   *
989
 *
990
   * XXX - TODO - FIXME - This should eventually be more general
990
 * XXX - TODO - FIXME - This should eventually be more general
991
   * deadlock detection of arbitrary length cycles */
991
 * deadlock detection of arbitrary length cycles */
992
  if (current->pid == fusd_dev->pid) {
992
 if (current->pid == fusd_dev->pid) {
993
    RDEBUG(3, "pid %d tried to open its own device (/dev/%s)",
993
 RDEBUG(3, "pid %d tried to open its own device (/dev/%s)",
994
	   fusd_dev->pid, NAME(fusd_dev));
994
 fusd_dev->pid, NAME(fusd_dev));
995
    return -EDEADLOCK;
995
 return -EDEADLOCK;
996
  }
996
 }
997
997
998
  /* make more space in the file array if we need it */
998
 /* make more space in the file array if we need it */
999
  if (fusd_dev->num_files == fusd_dev->array_size &&
999
 if (fusd_dev->num_files == fusd_dev->array_size &&
1000
      fusd_dev->array_size < MAX_FILEARRAY_SIZE)
1000
 fusd_dev->array_size < MAX_FILEARRAY_SIZE)
1001
    fusd_dev_adjsize(fusd_dev);
1001
 fusd_dev_adjsize(fusd_dev);
1002
1002
1003
  /* make sure we have room... adjsize may have failed */
1003
 /* make sure we have room... adjsize may have failed */
1004
  if (fusd_dev->num_files >= fusd_dev->array_size) {
1004
 if (fusd_dev->num_files >= fusd_dev->array_size) {
1005
    RDEBUG(1, "/dev/%s out of state space for open files!", NAME(fusd_dev));
1005
 RDEBUG(1, "/dev/%s out of state space for open files!", NAME(fusd_dev));
1006
    return -ENOMEM;
1006
 return -ENOMEM;
1007
  }
1007
 }
1008
1008
1009
  /* create state for this file */
1009
 /* create state for this file */
1010
  if ((fusd_file = KMALLOC(sizeof(fusd_file_t), GFP_KERNEL)) == NULL) {
1010
 if ((fusd_file = KMALLOC(sizeof(fusd_file_t), GFP_KERNEL)) == NULL) {
1011
    RDEBUG(1, "yikes!  kernel can't allocate memory");
1011
 RDEBUG(1, "yikes! kernel can't allocate memory");
1012
    return -ENOMEM;
1012
 return -ENOMEM;
1013
  }
1013
 }
1014
  memset(fusd_file, 0, sizeof(fusd_file_t));
1014
 memset(fusd_file, 0, sizeof(fusd_file_t));
1015
  init_waitqueue_head(&fusd_file->file_wait);
1015
 init_waitqueue_head(&fusd_file->file_wait);
1016
  init_waitqueue_head(&fusd_file->poll_wait);
1016
 init_waitqueue_head(&fusd_file->poll_wait);
1017
	INIT_LIST_HEAD(&fusd_file->transactions);
1017
 INIT_LIST_HEAD(&fusd_file->transactions);
1018
  init_MUTEX(&fusd_file->file_sem);
1018
 init_MUTEX(&fusd_file->file_sem);
1019
  init_MUTEX(&fusd_file->transactions_sem);
1019
 init_MUTEX(&fusd_file->transactions_sem);
1020
  fusd_file->last_poll_sent = -1;
1020
 fusd_file->last_poll_sent = -1;
1021
  fusd_file->magic = FUSD_FILE_MAGIC;
1021
 fusd_file->magic = FUSD_FILE_MAGIC;
1022
  fusd_file->fusd_dev = fusd_dev;
1022
 fusd_file->fusd_dev = fusd_dev;
1023
  fusd_file->fusd_dev_version = fusd_dev->version;
1023
 fusd_file->fusd_dev_version = fusd_dev->version;
1024
  fusd_file->file = file;
1024
 fusd_file->file = file;
1025
1025
1026
  /* add this file to the list of files managed by the device */
1026
 /* add this file to the list of files managed by the device */
1027
  fusd_file->index = fusd_dev->num_files++;
1027
 fusd_file->index = fusd_dev->num_files++;
1028
  fusd_dev->files[fusd_file->index] = fusd_file;
1028
 fusd_dev->files[fusd_file->index] = fusd_file;
1029
1029
1030
  /* store the pointer to this file with the kernel */
1030
 /* store the pointer to this file with the kernel */
1031
  file->private_data = fusd_file;
1031
 file->private_data = fusd_file;
1032
  *fusd_file_ret = fusd_file;
1032
 *fusd_file_ret = fusd_file;
1033
1033
1034
  /* success! */
1034
 /* success! */
1035
  return 0;
1035
 return 0;
1036
}
1036
}
1037
1037
1038
STATIC struct fusd_dev_t_s* find_user_device(int dev_id)
1038
STATIC struct fusd_dev_t_s* find_user_device(int dev_id)
1039
{
1039
{
1040
	struct list_head* entry;
1040
 struct list_head* entry;
1041
	down(&fusd_devlist_sem);
1041
 down(&fusd_devlist_sem);
1042
	list_for_each(entry, &fusd_devlist_head)
1042
 list_for_each(entry, &fusd_devlist_head)
1043
	{
1043
 {
1044
    fusd_dev_t *d = list_entry(entry, fusd_dev_t, devlist);
1044
 fusd_dev_t *d = list_entry(entry, fusd_dev_t, devlist);
1045
		if(d->dev_id == dev_id)
1045
 if(d->dev_id == dev_id)
1046
		{
1046
 {
1047
			up(&fusd_devlist_sem);
1047
 up(&fusd_devlist_sem);
1048
			return d;
1048
 return d;
1049
		}
1049
 }
1050
	}
1050
 }
1051
	up(&fusd_devlist_sem);
1051
 up(&fusd_devlist_sem);
1052
 return NULL;
1052
 return NULL;
1053
}
1053
}
1054
1054
Lines 1058-1667 Link Here
1058
 */
1058
 */
1059
STATIC int fusd_client_open(struct inode *inode, struct file *file)
1059
STATIC int fusd_client_open(struct inode *inode, struct file *file)
1060
{
1060
{
1061
  int retval;
1061
 int retval;
1062
  int device_freed = 0;
1062
 int device_freed = 0;
1063
  fusd_dev_t *fusd_dev = find_user_device(inode->i_rdev);
1063
 fusd_dev_t *fusd_dev = find_user_device(inode->i_rdev);
1064
  fusd_file_t *fusd_file;
1064
 fusd_file_t *fusd_file;
1065
  fusd_msg_t fusd_msg;
1065
 fusd_msg_t fusd_msg;
1066
  struct fusd_transaction* transaction;
1066
 struct fusd_transaction* transaction;
1067
  
1067
1068
  /* If the device wasn't on our valid list, stop here. */
1068
 /* If the device wasn't on our valid list, stop here. */
1069
  if (!fusd_dev_is_valid(fusd_dev))
1069
 if (!fusd_dev_is_valid(fusd_dev))
1070
    return -ENOENT;
1070
 return -ENOENT;
1071
1071
1072
  /* fusd_dev->open_in_progress now set */
1072
 /* fusd_dev->open_in_progress now set */
1073
1073
1074
  /* Lock the fusd device.  Note, when we finally do acquire the lock,
1074
 /* Lock the fusd device. Note, when we finally do acquire the lock,
1075
   * the device might be a zombie (driver disappeared). */
1075
 * the device might be a zombie (driver disappeared). */
1076
  RAWLOCK_FUSD_DEV(fusd_dev);
1076
 RAWLOCK_FUSD_DEV(fusd_dev);
1077
1077
1078
  RDEBUG(3, "got an open for /dev/%s (owned by pid %d) from pid %d",
1078
 RDEBUG(3, "got an open for /dev/%s (owned by pid %d) from pid %d",
1079
	 NAME(fusd_dev), fusd_dev->pid, current->pid);
1079
 NAME(fusd_dev), fusd_dev->pid, current->pid);
1080
1080
1081
  /* Try to add ourselves to the device's file list.  If retval==0, we
1081
 /* Try to add ourselves to the device's file list. If retval==0, we
1082
     are now part of the file array.  */
1082
 are now part of the file array. */
1083
  retval = fusd_dev_add_file(file, fusd_dev, &fusd_file);
1083
 retval = fusd_dev_add_file(file, fusd_dev, &fusd_file);
1084
1084
1085
  /*
1085
 /*
1086
   * It is now safe to unset the open_in_progress flag.  Either:
1086
 * It is now safe to unset the open_in_progress flag. Either:
1087
   *   1) We are part of the file array, so dev won't be freed, or;
1087
 * 1) We are part of the file array, so dev won't be freed, or;
1088
   *   2) Something failed, so we are returning a failure now and no
1088
 * 2) Something failed, so we are returning a failure now and no
1089
   *   longer need the device.
1089
 * longer need the device.
1090
   * Note, open_in_progress must be protected by the global sem, not
1090
 * Note, open_in_progress must be protected by the global sem, not
1091
   * the device lock, due to the access of it in fusd_dev_is_valid().
1091
 * the device lock, due to the access of it in fusd_dev_is_valid().
1092
   */
1092
 */
1093
  down(&fusd_devlist_sem);
1093
 down(&fusd_devlist_sem);
1094
  fusd_dev->open_in_progress--;
1094
 fusd_dev->open_in_progress--;
1095
  up(&fusd_devlist_sem);
1095
 up(&fusd_devlist_sem);
1096
1096
1097
  /* If adding ourselves to the device list failed, give up.  Possibly
1097
 /* If adding ourselves to the device list failed, give up. Possibly
1098
   * free the device if it was a zombie and waiting for us to complete
1098
 * free the device if it was a zombie and waiting for us to complete
1099
   * our open. */
1099
 * our open. */
1100
  if (retval < 0) {
1100
 if (retval < 0) {
1101
    if (!maybe_free_fusd_dev(fusd_dev))
1101
 if (!maybe_free_fusd_dev(fusd_dev))
1102
      UNLOCK_FUSD_DEV(fusd_dev);
1102
 UNLOCK_FUSD_DEV(fusd_dev);
1103
    return retval;
1103
 return retval;
1104
  }
1104
 }
1105
1105
1106
  /* send message to userspace and get retval */
1106
 /* send message to userspace and get retval */
1107
  init_fusd_msg(&fusd_msg);
1107
 init_fusd_msg(&fusd_msg);
1108
  fusd_msg.subcmd = FUSD_OPEN;
1108
 fusd_msg.subcmd = FUSD_OPEN;
1109
1109
1110
  /* send message to userspace and get the reply.  Device can't be
1110
 /* send message to userspace and get the reply. Device can't be
1111
   * locked during that operation. */
1111
 * locked during that operation. */
1112
1113
  UNLOCK_FUSD_DEV(fusd_dev);
1114
  retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction);
1115
  
1116
  if (retval >= 0)
1117
    retval = fusd_fops_call_wait(fusd_file, NULL, transaction);
1118
  RAWLOCK_FUSD_DEV(fusd_dev);
1119
1120
  /* If the device zombified (while we were waiting to reacquire the
1121
   * lock)... consider that a failure */
1122
  if (ZOMBIE(fusd_dev))
1123
    retval = -ENOENT;
1124
1125
  /* if retval is negative, throw away state... the file open failed */
1126
  if (retval < 0) {
1127
    RDEBUG(3, "...open failed for /dev/%s (owned by pid %d) from pid %d",
1128
	   NAME(fusd_dev), fusd_dev->pid, current->pid);
1129
1130
    device_freed = free_fusd_file(fusd_dev, fusd_file);
1131
  }
1132
1133
  /* Now unlock the device, if it still exists.  (It may have been
1134
   * freed if the open failed, and we were the last outstanding
1135
   * request for it.) */
1136
  if (!device_freed)
1137
    UNLOCK_FUSD_DEV(fusd_dev);
1138
1112
1139
  return retval;
1113
 UNLOCK_FUSD_DEV(fusd_dev);
1114
 retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction);
1115
1116
 if (retval >= 0)
1117
 retval = fusd_fops_call_wait(fusd_file, NULL, transaction);
1118
 RAWLOCK_FUSD_DEV(fusd_dev);
1119
1120
 /* If the device zombified (while we were waiting to reacquire the
1121
 * lock)... consider that a failure */
1122
 if (ZOMBIE(fusd_dev))
1123
 retval = -ENOENT;
1124
1125
 /* if retval is negative, throw away state... the file open failed */
1126
 if (retval < 0) {
1127
 RDEBUG(3, "...open failed for /dev/%s (owned by pid %d) from pid %d",
1128
 NAME(fusd_dev), fusd_dev->pid, current->pid);
1129
1130
 device_freed = free_fusd_file(fusd_dev, fusd_file);
1131
 }
1132
1133
 /* Now unlock the device, if it still exists. (It may have been
1134
 * freed if the open failed, and we were the last outstanding
1135
 * request for it.) */
1136
 if (!device_freed)
1137
 UNLOCK_FUSD_DEV(fusd_dev);
1138
1139
 return retval;
1140
}
1140
}
1141
1141
1142
1142
1143
/* close() has been called on a registered device.  like
1143
/* close() has been called on a registered device. like
1144
 * fusd_client_open, we must lock the entire device. */
1144
 * fusd_client_open, we must lock the entire device. */
1145
STATIC int fusd_client_release(struct inode *inode, struct file *file)
1145
STATIC int fusd_client_release(struct inode *inode, struct file *file)
1146
{
1146
{
1147
  int retval;
1147
 int retval;
1148
  fusd_file_t *fusd_file;
1148
 fusd_file_t *fusd_file;
1149
  fusd_dev_t *fusd_dev;
1149
 fusd_dev_t *fusd_dev;
1150
  fusd_msg_t fusd_msg;
1150
 fusd_msg_t fusd_msg;
1151
  struct fusd_transaction* transaction;
1151
 struct fusd_transaction* transaction;
1152
  
1152
1153
  GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev);
1153
 GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev);
1154
  LOCK_FUSD_FILE(fusd_file);
1154
 LOCK_FUSD_FILE(fusd_file);
1155
1155
1156
  RDEBUG(3, "got a close on /dev/%s (owned by pid %d) from pid %d",
1156
 RDEBUG(3, "got a close on /dev/%s (owned by pid %d) from pid %d",
1157
	 NAME(fusd_dev), fusd_dev->pid, current->pid);
1157
 NAME(fusd_dev), fusd_dev->pid, current->pid);
1158
1158
1159
  /* Tell the driver that the file closed, if it still exists. */
1159
 /* Tell the driver that the file closed, if it still exists. */
1160
  init_fusd_msg(&fusd_msg);
1160
 init_fusd_msg(&fusd_msg);
1161
  fusd_msg.subcmd = FUSD_CLOSE;
1161
 fusd_msg.subcmd = FUSD_CLOSE;
1162
  retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction);
1162
 retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction);
1163
	RDEBUG(5, "fusd_client_release: send returned %d", retval);
1163
 RDEBUG(5, "fusd_client_release: send returned %d", retval);
1164
  if (retval >= 0)
1164
 if (retval >= 0)
1165
    retval = fusd_fops_call_wait(fusd_file, NULL, transaction);
1165
 retval = fusd_fops_call_wait(fusd_file, NULL, transaction);
1166
	
1166
1167
	RDEBUG(5, "fusd_client_release: call_wait %d", retval);
1167
 RDEBUG(5, "fusd_client_release: call_wait %d", retval);
1168
  /* delete the file off the device's file-list, and free it.  note
1168
 /* delete the file off the device's file-list, and free it. note
1169
   * that device may be a zombie right now and may be freed when we
1169
 * that device may be a zombie right now and may be freed when we
1170
   * come back from free_fusd_file.  we only release the lock if the
1170
 * come back from free_fusd_file. we only release the lock if the
1171
   * device still exists. */
1171
 * device still exists. */
1172
  RAWLOCK_FUSD_DEV(fusd_dev);
1172
 RAWLOCK_FUSD_DEV(fusd_dev);
1173
  if (!free_fusd_file(fusd_dev, fusd_file)) {
1173
 if (!free_fusd_file(fusd_dev, fusd_file)) {
1174
    UNLOCK_FUSD_DEV(fusd_dev);
1174
 UNLOCK_FUSD_DEV(fusd_dev);
1175
  }
1175
 }
1176
1176
1177
  return retval;
1177
 return retval;
1178
1178
1179
 invalid_dev:
1179
 invalid_dev:
1180
 invalid_file:
1180
 invalid_file:
1181
  RDEBUG(1, "got a close on client file from pid %d, INVALID DEVICE!",
1181
 RDEBUG(1, "got a close on client file from pid %d, INVALID DEVICE!",
1182
	 current->pid);
1182
 current->pid);
1183
  return -EPIPE;
1183
 return -EPIPE;
1184
}
1184
}
1185
1185
1186
1186
1187
1187
1188
STATIC ssize_t fusd_client_read(struct file *file , char *buf,
1188
STATIC ssize_t fusd_client_read(struct file *file , char *buf,
1189
			 size_t count, loff_t *offset)
1189
 size_t count, loff_t *offset)
1190
{
1190
{
1191
  fusd_dev_t *fusd_dev;
1191
 fusd_dev_t *fusd_dev;
1192
  fusd_file_t *fusd_file;
1192
 fusd_file_t *fusd_file;
1193
  struct fusd_transaction* transaction;
1193
 struct fusd_transaction* transaction;
1194
  fusd_msg_t fusd_msg, *reply = NULL;
1194
 fusd_msg_t fusd_msg, *reply = NULL;
1195
  int retval = -EPIPE;
1195
 int retval = -EPIPE;
1196
1196
1197
  GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev);
1197
 GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev);
1198
  LOCK_FUSD_FILE(fusd_file);
1198
 LOCK_FUSD_FILE(fusd_file);
1199
1199
1200
  RDEBUG(3, "got a read on /dev/%s (owned by pid %d) from pid %d",
1200
 RDEBUG(3, "got a read on /dev/%s (owned by pid %d) from pid %d",
1201
	 NAME(fusd_dev), fusd_dev->pid, current->pid);
1201
 NAME(fusd_dev), fusd_dev->pid, current->pid);
1202
1202
1203
  transaction = fusd_find_incomplete_transaction(fusd_file, FUSD_READ);
1203
 transaction = fusd_find_incomplete_transaction(fusd_file, FUSD_READ);
1204
  if (transaction && transaction->size > count)
1204
 if (transaction && transaction->size > count)
1205
  {
1205
 {
1206
    RDEBUG(3, "Incomplete I/O transaction %ld thrown out, as the transaction's size of %d bytes was greater than "
1206
 RDEBUG(3, "Incomplete I/O transaction %ld thrown out, as the transaction's size of %d bytes was greater than "
1207
              "the retry's size of %d bytes", transaction->transid, transaction->size, (int)count);
1207
 "the retry's size of %d bytes", transaction->transid, transaction->size, (int)count);
1208
1208
1209
    fusd_cleanup_transaction(fusd_file, transaction);
1209
 fusd_cleanup_transaction(fusd_file, transaction);
1210
    transaction = NULL;
1210
 transaction = NULL;
1211
  }
1211
 }
1212
1212
1213
  if(transaction == NULL)
1213
 if(transaction == NULL)
1214
  {
1214
 {
1215
    /* make sure we aren't trying to read too big of a buffer */
1215
 /* make sure we aren't trying to read too big of a buffer */
1216
    if (count > MAX_RW_SIZE)
1216
 if (count > MAX_RW_SIZE)
1217
      count = MAX_RW_SIZE;
1217
 count = MAX_RW_SIZE;
1218
  
1218
1219
    /* send the message */
1219
 /* send the message */
1220
    init_fusd_msg(&fusd_msg);
1220
 init_fusd_msg(&fusd_msg);
1221
    fusd_msg.subcmd = FUSD_READ;
1221
 fusd_msg.subcmd = FUSD_READ;
1222
    fusd_msg.parm.fops_msg.length = count;
1222
 fusd_msg.parm.fops_msg.length = count;
1223
  
1223
1224
    /* send message to userspace */
1224
 /* send message to userspace */
1225
    if ((retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction)) < 0)
1225
 if ((retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction)) < 0)
1226
      goto done;
1226
 goto done;
1227
  }
1227
 }
1228
  
1228
1229
  /* and wait for the reply */
1229
 /* and wait for the reply */
1230
  /* todo: store and retrieve the transid from the interrupted messsage */
1230
 /* todo: store and retrieve the transid from the interrupted messsage */
1231
  retval = fusd_fops_call_wait(fusd_file, &reply, transaction);
1231
 retval = fusd_fops_call_wait(fusd_file, &reply, transaction);
1232
1232
1233
  /* return immediately in case of error */
1233
 /* return immediately in case of error */
1234
  if (retval < 0 || reply == NULL)
1234
 if (retval < 0 || reply == NULL)
1235
    goto done;
1235
 goto done;
1236
1236
1237
  /* adjust the reval if the retval indicates a larger read than the
1237
 /* adjust the reval if the retval indicates a larger read than the
1238
   * data that was actually provided */
1238
 * data that was actually provided */
1239
  if (reply->datalen != retval) {
1239
 if (reply->datalen != retval) {
1240
    RDEBUG(1, "warning: /dev/%s driver (pid %d) claimed it returned %d bytes "
1240
 RDEBUG(1, "warning: /dev/%s driver (pid %d) claimed it returned %d bytes "
1241
	   "on read but actually returned %d", 
1241
 "on read but actually returned %d",
1242
	   NAME(fusd_dev), fusd_dev->pid, retval, reply->datalen);
1242
 NAME(fusd_dev), fusd_dev->pid, retval, reply->datalen);
1243
    retval = reply->datalen;
1243
 retval = reply->datalen;
1244
  }
1244
 }
1245
1245
1246
  /* adjust if the device driver gave us more data than the user asked for
1246
 /* adjust if the device driver gave us more data than the user asked for
1247
   *     (bad!  bad!  why is the driver broken???) */
1247
 * (bad! bad! why is the driver broken???) */
1248
  if (retval > count) {
1248
 if (retval > count) {
1249
    RDEBUG(1, "warning: /dev/%s driver (pid %d) returned %d bytes on read but "
1249
 RDEBUG(1, "warning: /dev/%s driver (pid %d) returned %d bytes on read but "
1250
	   "the user only asked for %d", 
1250
 "the user only asked for %d",
1251
	   NAME(fusd_dev), fusd_dev->pid, retval, (int) count);
1251
 NAME(fusd_dev), fusd_dev->pid, retval, (int) count);
1252
    retval = count;
1252
 retval = count;
1253
  }
1253
 }
1254
1254
1255
  /* copy the offset back from the message */
1255
 /* copy the offset back from the message */
1256
  *offset = reply->parm.fops_msg.offset;
1256
 *offset = reply->parm.fops_msg.offset;
1257
1257
1258
  /* IFF return value indicates data present, copy it back */
1258
 /* IFF return value indicates data present, copy it back */
1259
  if (retval > 0) {
1259
 if (retval > 0) {
1260
    if (copy_to_user(buf, reply->data, retval)) {
1260
 if (copy_to_user(buf, reply->data, retval)) {
1261
      retval = -EFAULT;
1261
 retval = -EFAULT;
1262
      goto done;
1262
 goto done;
1263
    }
1263
 }
1264
  }
1264
 }
1265
1265
1266
 done:
1266
 done:
1267
  /* clear the readable bit of our cached poll state */
1267
 /* clear the readable bit of our cached poll state */
1268
  fusd_file->cached_poll_state &= ~(FUSD_NOTIFY_INPUT);
1268
 fusd_file->cached_poll_state &= ~(FUSD_NOTIFY_INPUT);
1269
1269
1270
  free_fusd_msg(&reply);
1270
 free_fusd_msg(&reply);
1271
  UNLOCK_FUSD_FILE(fusd_file);
1271
 UNLOCK_FUSD_FILE(fusd_file);
1272
  return retval;
1272
 return retval;
1273
1273
1274
 invalid_file:
1274
 invalid_file:
1275
 invalid_dev:
1275
 invalid_dev:
1276
  RDEBUG(3, "got a read on client file from pid %d, driver has disappeared",
1276
 RDEBUG(3, "got a read on client file from pid %d, driver has disappeared",
1277
	 current->pid);
1277
 current->pid);
1278
  return -EPIPE;
1278
 return -EPIPE;
1279
}
1279
}
1280
1280
1281
STATIC int fusd_add_transaction(fusd_file_t *fusd_file, int transid, int subcmd, int size, struct fusd_transaction** out_transaction)
1281
STATIC int fusd_add_transaction(fusd_file_t *fusd_file, int transid, int subcmd, int size, struct fusd_transaction** out_transaction)
1282
{
1282
{
1283
	struct fusd_transaction* transaction = (struct fusd_transaction*) KMALLOC(sizeof(struct fusd_transaction), GFP_KERNEL);
1283
 struct fusd_transaction* transaction = (struct fusd_transaction*) KMALLOC(sizeof(struct fusd_transaction), GFP_KERNEL);
1284
	if(transaction == NULL)
1284
 if(transaction == NULL)
1285
		return -ENOMEM;
1285
 return -ENOMEM;
1286
	
1286
1287
	transaction->msg_in = NULL;
1287
 transaction->msg_in = NULL;
1288
	transaction->transid = transid;
1288
 transaction->transid = transid;
1289
	transaction->subcmd = subcmd;
1289
 transaction->subcmd = subcmd;
1290
	transaction->pid = current->pid;
1290
 transaction->pid = current->pid;
1291
	transaction->size = size;
1291
 transaction->size = size;
1292
	
1292
1293
	down(&fusd_file->transactions_sem);
1293
 down(&fusd_file->transactions_sem);
1294
	list_add_tail(&transaction->list, &fusd_file->transactions);
1294
 list_add_tail(&transaction->list, &fusd_file->transactions);
1295
	up(&fusd_file->transactions_sem);
1295
 up(&fusd_file->transactions_sem);
1296
	
1296
1297
	if(out_transaction != NULL)
1297
 if(out_transaction != NULL)
1298
		*out_transaction = transaction;
1298
 *out_transaction = transaction;
1299
	
1299
1300
	return 0;
1300
 return 0;
1301
}
1301
}
1302
1302
1303
STATIC void fusd_cleanup_transaction(fusd_file_t *fusd_file, struct fusd_transaction* transaction)
1303
STATIC void fusd_cleanup_transaction(fusd_file_t *fusd_file, struct fusd_transaction* transaction)
1304
{
1304
{
1305
  free_fusd_msg(&transaction->msg_in);
1305
 free_fusd_msg(&transaction->msg_in);
1306
  fusd_remove_transaction(fusd_file, transaction);
1306
 fusd_remove_transaction(fusd_file, transaction);
1307
}
1307
}
1308
1308
1309
STATIC void fusd_remove_transaction(fusd_file_t *fusd_file, struct fusd_transaction* transaction)
1309
STATIC void fusd_remove_transaction(fusd_file_t *fusd_file, struct fusd_transaction* transaction)
1310
{
1310
{
1311
	down(&fusd_file->transactions_sem);
1311
 down(&fusd_file->transactions_sem);
1312
	list_del(&transaction->list);
1312
 list_del(&transaction->list);
1313
	up(&fusd_file->transactions_sem);
1313
 up(&fusd_file->transactions_sem);
1314
	
1314
1315
	KFREE(transaction);
1315
 KFREE(transaction);
1316
}
1316
}
1317
1317
1318
STATIC struct fusd_transaction* fusd_find_transaction(fusd_file_t *fusd_file, int transid)
1318
STATIC struct fusd_transaction* fusd_find_transaction(fusd_file_t *fusd_file, int transid)
1319
{
1319
{
1320
	struct list_head* i;
1320
 struct list_head* i;
1321
	down(&fusd_file->transactions_sem);
1321
 down(&fusd_file->transactions_sem);
1322
	list_for_each(i, &fusd_file->transactions)
1322
 list_for_each(i, &fusd_file->transactions)
1323
	{
1323
 {
1324
		struct fusd_transaction* transaction = list_entry(i, struct fusd_transaction, list);
1324
 struct fusd_transaction* transaction = list_entry(i, struct fusd_transaction, list);
1325
		if(transaction->transid == transid)
1325
 if(transaction->transid == transid)
1326
		{
1326
 {
1327
			up(&fusd_file->transactions_sem);
1327
 up(&fusd_file->transactions_sem);
1328
			return transaction;
1328
 return transaction;
1329
		}
1329
 }
1330
	}
1330
 }
1331
	up(&fusd_file->transactions_sem);
1331
 up(&fusd_file->transactions_sem);
1332
	return NULL;
1332
 return NULL;
1333
}
1333
}
1334
1334
1335
STATIC struct fusd_transaction* fusd_find_transaction_by_pid(fusd_file_t *fusd_file, int pid)
1335
STATIC struct fusd_transaction* fusd_find_transaction_by_pid(fusd_file_t *fusd_file, int pid)
1336
{
1336
{
1337
	struct list_head* i;
1337
 struct list_head* i;
1338
	down(&fusd_file->transactions_sem);
1338
 down(&fusd_file->transactions_sem);
1339
	list_for_each(i, &fusd_file->transactions)
1339
 list_for_each(i, &fusd_file->transactions)
1340
	{
1340
 {
1341
		struct fusd_transaction* transaction = list_entry(i, struct fusd_transaction, list);
1341
 struct fusd_transaction* transaction = list_entry(i, struct fusd_transaction, list);
1342
		if(transaction->pid == pid)
1342
 if(transaction->pid == pid)
1343
		{
1343
 {
1344
			up(&fusd_file->transactions_sem);
1344
 up(&fusd_file->transactions_sem);
1345
			return transaction;
1345
 return transaction;
1346
		}
1346
 }
1347
	}
1347
 }
1348
	up(&fusd_file->transactions_sem);
1348
 up(&fusd_file->transactions_sem);
1349
	return NULL;
1349
 return NULL;
1350
}
1350
}
1351
1351
1352
STATIC ssize_t fusd_client_write(struct file *file,
1352
STATIC ssize_t fusd_client_write(struct file *file,
1353
    const char *buffer,
1353
 const char *buffer,
1354
    size_t length,
1354
 size_t length,
1355
    loff_t *offset)
1355
 loff_t *offset)
1356
{
1356
{
1357
  fusd_dev_t *fusd_dev;
1357
 fusd_dev_t *fusd_dev;
1358
  fusd_file_t *fusd_file;
1358
 fusd_file_t *fusd_file;
1359
  fusd_msg_t fusd_msg;
1359
 fusd_msg_t fusd_msg;
1360
  fusd_msg_t *reply = NULL;
1360
 fusd_msg_t *reply = NULL;
1361
  int retval = -EPIPE;
1361
 int retval = -EPIPE;
1362
  struct fusd_transaction* transaction;
1362
 struct fusd_transaction* transaction;
1363
  
1363
1364
  GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev);
1364
 GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev);
1365
  LOCK_FUSD_FILE(fusd_file);
1365
 LOCK_FUSD_FILE(fusd_file);
1366
1366
1367
  RDEBUG(3, "got a write on /dev/%s (owned by pid %d) from pid %d",
1367
 RDEBUG(3, "got a write on /dev/%s (owned by pid %d) from pid %d",
1368
	 NAME(fusd_dev), fusd_dev->pid, current->pid);
1368
 NAME(fusd_dev), fusd_dev->pid, current->pid);
1369
1369
1370
  transaction = fusd_find_incomplete_transaction(fusd_file, FUSD_WRITE);
1370
 transaction = fusd_find_incomplete_transaction(fusd_file, FUSD_WRITE);
1371
  if (transaction && transaction->size == length)
1371
 if (transaction && transaction->size == length)
1372
  {
1372
 {
1373
    RDEBUG(2, "Incomplete I/O transaction %ld thrown out, as the transaction's size of %d bytes was not equal to "
1373
 RDEBUG(2, "Incomplete I/O transaction %ld thrown out, as the transaction's size of %d bytes was not equal to "
1374
              "the retry's size of %d bytes", transaction->transid, transaction->size, (int) length);
1374
 "the retry's size of %d bytes", transaction->transid, transaction->size, (int) length);
1375
1375
1376
    fusd_cleanup_transaction(fusd_file, transaction);
1376
 fusd_cleanup_transaction(fusd_file, transaction);
1377
    transaction = NULL;
1377
 transaction = NULL;
1378
  }
1378
 }
1379
  if(transaction == NULL)
1379
 if(transaction == NULL)
1380
  {
1380
 {
1381
    if (length < 0) {
1381
 if (length < 0) {
1382
      RDEBUG(2, "fusd_client_write: got invalid length %d", (int) length);
1382
 RDEBUG(2, "fusd_client_write: got invalid length %d", (int) length);
1383
      retval = -EINVAL;
1383
 retval = -EINVAL;
1384
      goto done;
1384
 goto done;
1385
    }
1385
 }
1386
  
1386
1387
    if (length > MAX_RW_SIZE)
1387
 if (length > MAX_RW_SIZE)
1388
      length = MAX_RW_SIZE;
1388
 length = MAX_RW_SIZE;
1389
  
1389
1390
    init_fusd_msg(&fusd_msg);
1390
 init_fusd_msg(&fusd_msg);
1391
  
1391
1392
    /* sigh.. i guess zero length writes should be legal */
1392
 /* sigh.. i guess zero length writes should be legal */
1393
    if (length > 0) {
1393
 if (length > 0) {
1394
      if ((fusd_msg.data = VMALLOC(length)) == NULL) {
1394
 if ((fusd_msg.data = VMALLOC(length)) == NULL) {
1395
        retval = -ENOMEM;
1395
 retval = -ENOMEM;
1396
        goto done;
1396
 goto done;
1397
      }
1397
 }
1398
  
1398
1399
      if (copy_from_user(fusd_msg.data, buffer, length)) {
1399
 if (copy_from_user(fusd_msg.data, buffer, length)) {
1400
        retval = -EFAULT;
1400
 retval = -EFAULT;
1401
        goto done;
1401
 goto done;
1402
      }
1402
 }
1403
      fusd_msg.datalen = length;
1403
 fusd_msg.datalen = length;
1404
    }
1404
 }
1405
    
1405
1406
    fusd_msg.subcmd = FUSD_WRITE;
1406
 fusd_msg.subcmd = FUSD_WRITE;
1407
    fusd_msg.parm.fops_msg.length = length;
1407
 fusd_msg.parm.fops_msg.length = length;
1408
    
1408
1409
    if ((retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction)) < 0)
1409
 if ((retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction)) < 0)
1410
      goto done;
1410
 goto done;
1411
  }
1411
 }
1412
	/* todo: fix transid on restart */
1412
 /* todo: fix transid on restart */
1413
  retval = fusd_fops_call_wait(fusd_file, &reply, transaction);
1413
 retval = fusd_fops_call_wait(fusd_file, &reply, transaction);
1414
1414
1415
  if (retval < 0 || reply == NULL)
1415
 if (retval < 0 || reply == NULL)
1416
    goto done;
1416
 goto done;
1417
1417
1418
  /* drivers should not write more bytes than they were asked to! */
1418
 /* drivers should not write more bytes than they were asked to! */
1419
  if (retval > length) {
1419
 if (retval > length) {
1420
    RDEBUG(1, "warning: /dev/%s driver (pid %d) returned %d bytes on write; "
1420
 RDEBUG(1, "warning: /dev/%s driver (pid %d) returned %d bytes on write; "
1421
	   "the user only wanted %d", 
1421
 "the user only wanted %d",
1422
	   NAME(fusd_dev), fusd_dev->pid, retval, (int) length);
1422
 NAME(fusd_dev), fusd_dev->pid, retval, (int) length);
1423
    retval = length;
1423
 retval = length;
1424
  }
1424
 }
1425
1425
1426
  *offset = reply->parm.fops_msg.offset;
1426
 *offset = reply->parm.fops_msg.offset;
1427
1427
1428
  /* all done! */
1428
 /* all done! */
1429
1429
1430
 done:
1430
 done:
1431
  /* clear the writable bit of our cached poll state */
1431
 /* clear the writable bit of our cached poll state */
1432
  fusd_file->cached_poll_state &= ~(FUSD_NOTIFY_OUTPUT);
1432
 fusd_file->cached_poll_state &= ~(FUSD_NOTIFY_OUTPUT);
1433
1433
1434
  free_fusd_msg(&reply);
1434
 free_fusd_msg(&reply);
1435
  UNLOCK_FUSD_FILE(fusd_file);
1435
 UNLOCK_FUSD_FILE(fusd_file);
1436
  return retval;
1436
 return retval;
1437
1437
1438
 invalid_file:
1438
 invalid_file:
1439
 invalid_dev:
1439
 invalid_dev:
1440
  RDEBUG(3, "got a read on client file from pid %d, driver has disappeared",
1440
 RDEBUG(3, "got a read on client file from pid %d, driver has disappeared",
1441
	 current->pid);
1441
 current->pid);
1442
  return -EPIPE;
1442
 return -EPIPE;
1443
}
1443
}
1444
1444
1445
1445
1446
STATIC int fusd_client_ioctl(struct inode *inode, struct file *file,
1446
STATIC int fusd_client_ioctl(struct inode *inode, struct file *file,
1447
				 unsigned int cmd, unsigned long arg)
1447
 unsigned int cmd, unsigned long arg)
1448
{
1448
{
1449
  fusd_dev_t *fusd_dev;
1449
 fusd_dev_t *fusd_dev;
1450
  fusd_file_t *fusd_file;
1450
 fusd_file_t *fusd_file;
1451
  fusd_msg_t fusd_msg, *reply = NULL;
1451
 fusd_msg_t fusd_msg, *reply = NULL;
1452
  int retval = -EPIPE, dir, length;
1452
 int retval = -EPIPE, dir, length;
1453
  struct fusd_transaction* transaction;
1453
 struct fusd_transaction* transaction;
1454
  
1454
1455
  GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev);
1455
 GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev);
1456
  LOCK_FUSD_FILE(fusd_file);
1456
 LOCK_FUSD_FILE(fusd_file);
1457
1457
1458
  RDEBUG(3, "got an ioctl on /dev/%s (owned by pid %d) from pid %d",
1458
 RDEBUG(3, "got an ioctl on /dev/%s (owned by pid %d) from pid %d",
1459
	 NAME(fusd_dev), fusd_dev->pid, current->pid);
1459
 NAME(fusd_dev), fusd_dev->pid, current->pid);
1460
1460
1461
  dir = _IOC_DIR(cmd);
1461
 dir = _IOC_DIR(cmd);
1462
  length = _IOC_SIZE(cmd);
1462
 length = _IOC_SIZE(cmd);
1463
1463
1464
  transaction = fusd_find_incomplete_transaction(fusd_file, FUSD_IOCTL);
1464
 transaction = fusd_find_incomplete_transaction(fusd_file, FUSD_IOCTL);
1465
  // todo: Check to make sure the transaction is for the same IOCTL
1465
 // todo: Check to make sure the transaction is for the same IOCTL
1466
1466
1467
  if(transaction == NULL)
1467
 if(transaction == NULL)
1468
  {
1468
 {
1469
    /* if we're trying to read or write, make sure length is sane */
1469
 /* if we're trying to read or write, make sure length is sane */
1470
    if ((dir & (_IOC_WRITE | _IOC_READ)) &&
1470
 if ((dir & (_IOC_WRITE | _IOC_READ)) &&
1471
        (length <= 0 || length > MAX_RW_SIZE))
1471
 (length <= 0 || length > MAX_RW_SIZE))
1472
      {
1472
 {
1473
        RDEBUG(2, "client ioctl got crazy IOC_SIZE of %d", length);
1473
 RDEBUG(2, "client ioctl got crazy IOC_SIZE of %d", length);
1474
        retval = -EINVAL;
1474
 retval = -EINVAL;
1475
        goto done;
1475
 goto done;
1476
      }
1476
 }
1477
  
1477
1478
    /* fill the struct */
1478
 /* fill the struct */
1479
    init_fusd_msg(&fusd_msg);
1479
 init_fusd_msg(&fusd_msg);
1480
    fusd_msg.subcmd = FUSD_IOCTL;
1480
 fusd_msg.subcmd = FUSD_IOCTL;
1481
    fusd_msg.parm.fops_msg.cmd = cmd;
1481
 fusd_msg.parm.fops_msg.cmd = cmd;
1482
    fusd_msg.parm.fops_msg.arg = arg;
1482
 fusd_msg.parm.fops_msg.arg = arg;
1483
  
1483
1484
    /* get the data if user is trying to write to the driver */
1484
 /* get the data if user is trying to write to the driver */
1485
    if (dir & _IOC_WRITE) {
1485
 if (dir & _IOC_WRITE) {
1486
      if ((fusd_msg.data = VMALLOC(length)) == NULL) {
1486
 if ((fusd_msg.data = VMALLOC(length)) == NULL) {
1487
        RDEBUG(2, "can't vmalloc for client ioctl!");
1487
 RDEBUG(2, "can't vmalloc for client ioctl!");
1488
        retval = -ENOMEM;
1488
 retval = -ENOMEM;
1489
        goto done;
1489
 goto done;
1490
      }
1490
 }
1491
  
1491
1492
      if (copy_from_user(fusd_msg.data, (void *) arg, length)) {
1492
 if (copy_from_user(fusd_msg.data, (void *) arg, length)) {
1493
        retval = -EFAULT;
1493
 retval = -EFAULT;
1494
        goto done;
1494
 goto done;
1495
      }
1495
 }
1496
      fusd_msg.datalen = length;
1496
 fusd_msg.datalen = length;
1497
    }
1497
 }
1498
  
1498
1499
    /* send request to the driver */
1499
 /* send request to the driver */
1500
    if ((retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction)) < 0)
1500
 if ((retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction)) < 0)
1501
      goto done;
1501
 goto done;
1502
  }
1502
 }
1503
  /* get the response */
1503
 /* get the response */
1504
	/* todo: fix transid on restart */
1504
 /* todo: fix transid on restart */
1505
  if ((retval = fusd_fops_call_wait(fusd_file, &reply, transaction)) < 0 || reply == NULL)
1505
 if ((retval = fusd_fops_call_wait(fusd_file, &reply, transaction)) < 0 || reply == NULL)
1506
    goto done;
1506
 goto done;
1507
1507
1508
  /* if user is trying to read from the driver, copy data back */
1508
 /* if user is trying to read from the driver, copy data back */
1509
  if (dir & _IOC_READ) {
1509
 if (dir & _IOC_READ) {
1510
    if (reply->data == NULL || reply->datalen != length) {
1510
 if (reply->data == NULL || reply->datalen != length) {
1511
      RDEBUG(2, "client_ioctl read reply with screwy data (%d, %d)",
1511
 RDEBUG(2, "client_ioctl read reply with screwy data (%d, %d)",
1512
	     reply->datalen, length);
1512
 reply->datalen, length);
1513
      retval = -EIO;
1513
 retval = -EIO;
1514
      goto done;
1514
 goto done;
1515
    }
1515
 }
1516
    if (copy_to_user((void *)arg, reply->data, length)) {
1516
 if (copy_to_user((void *)arg, reply->data, length)) {
1517
      retval = -EFAULT;
1517
 retval = -EFAULT;
1518
      goto done;
1518
 goto done;
1519
    }
1519
 }
1520
  }
1520
 }
1521
1521
1522
  /* all done! */
1522
 /* all done! */
1523
 done:
1523
 done:
1524
  free_fusd_msg(&reply);
1524
 free_fusd_msg(&reply);
1525
  UNLOCK_FUSD_FILE(fusd_file);
1525
 UNLOCK_FUSD_FILE(fusd_file);
1526
  return retval;
1526
 return retval;
1527
1527
1528
 invalid_file:
1528
 invalid_file:
1529
 invalid_dev:
1529
 invalid_dev:
1530
  RDEBUG(3, "got a read on client file from pid %d, driver has disappeared",
1530
 RDEBUG(3, "got a read on client file from pid %d, driver has disappeared",
1531
	 current->pid);
1531
 current->pid);
1532
  return -EPIPE;
1532
 return -EPIPE;
1533
}
1533
}
1534
static void fusd_client_mm_open(struct vm_area_struct * vma);
1534
static void fusd_client_mm_open(struct vm_area_struct * vma);
1535
static void fusd_client_mm_close(struct vm_area_struct * vma);
1535
static void fusd_client_mm_close(struct vm_area_struct * vma);
1536
static struct page* fusd_client_nopage(struct vm_area_struct* vma, unsigned long address, int* type);
1536
static struct page* fusd_client_nopage(struct vm_area_struct* vma, unsigned long address, int* type);
1537
static struct vm_operations_struct fusd_remap_vm_ops =
1537
static struct vm_operations_struct fusd_remap_vm_ops =
1538
{
1538
{
1539
  open: fusd_client_mm_open,
1539
 open: fusd_client_mm_open,
1540
  close: fusd_client_mm_close,
1540
 close: fusd_client_mm_close,
1541
  nopage: fusd_client_nopage,
1541
 nopage: fusd_client_nopage,
1542
};
1542
};
1543
1543
1544
struct fusd_mmap_instance
1544
struct fusd_mmap_instance
1545
{
1545
{
1546
  fusd_dev_t* fusd_dev;
1546
 fusd_dev_t* fusd_dev;
1547
  fusd_file_t* fusd_file;
1547
 fusd_file_t* fusd_file;
1548
  unsigned long addr;
1548
 unsigned long addr;
1549
  int size;
1549
 int size;
1550
  atomic_t refcount;
1550
 atomic_t refcount;
1551
};
1551
};
1552
1552
1553
static void fusd_client_mm_open(struct vm_area_struct * vma)
1553
static void fusd_client_mm_open(struct vm_area_struct * vma)
1554
{
1554
{
1555
  struct fusd_mmap_instance* mmap_instance = (struct fusd_mmap_instance*) vma->vm_private_data;
1555
 struct fusd_mmap_instance* mmap_instance = (struct fusd_mmap_instance*) vma->vm_private_data;
1556
  atomic_inc(&mmap_instance->refcount);
1556
 atomic_inc(&mmap_instance->refcount);
1557
  
1557
1558
}
1558
}
1559
1559
1560
static void fusd_client_mm_close(struct vm_area_struct * vma)
1560
static void fusd_client_mm_close(struct vm_area_struct * vma)
1561
{
1561
{
1562
  struct fusd_mmap_instance* mmap_instance = (struct fusd_mmap_instance*) vma->vm_private_data;
1562
 struct fusd_mmap_instance* mmap_instance = (struct fusd_mmap_instance*) vma->vm_private_data;
1563
  if(atomic_dec_and_test(&mmap_instance->refcount))
1563
 if(atomic_dec_and_test(&mmap_instance->refcount))
1564
  {
1564
 {
1565
    KFREE(mmap_instance);
1565
 KFREE(mmap_instance);
1566
  }
1566
 }
1567
}
1567
}
1568
1568
1569
static int fusd_client_mmap(struct file *file, struct vm_area_struct * vma)
1569
static int fusd_client_mmap(struct file *file, struct vm_area_struct * vma)
1570
{
1570
{
1571
  fusd_dev_t *fusd_dev;
1571
 fusd_dev_t *fusd_dev;
1572
  fusd_file_t *fusd_file;
1572
 fusd_file_t *fusd_file;
1573
  struct fusd_transaction* transaction;
1573
 struct fusd_transaction* transaction;
1574
  fusd_msg_t fusd_msg, *reply = NULL;
1574
 fusd_msg_t fusd_msg, *reply = NULL;
1575
  int retval = -EPIPE;
1575
 int retval = -EPIPE;
1576
  struct fusd_mmap_instance* mmap_instance;
1576
 struct fusd_mmap_instance* mmap_instance;
1577
1577
1578
  GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev);
1578
 GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev);
1579
  LOCK_FUSD_FILE(fusd_file);
1579
 LOCK_FUSD_FILE(fusd_file);
1580
1580
1581
  RDEBUG(3, "got a mmap on /dev/%s (owned by pid %d) from pid %d",
1581
 RDEBUG(3, "got a mmap on /dev/%s (owned by pid %d) from pid %d",
1582
	 NAME(fusd_dev), fusd_dev->pid, current->pid);
1582
 NAME(fusd_dev), fusd_dev->pid, current->pid);
1583
1583
1584
  transaction = fusd_find_incomplete_transaction(fusd_file, FUSD_MMAP);
1584
 transaction = fusd_find_incomplete_transaction(fusd_file, FUSD_MMAP);
1585
1585
1586
  if(transaction == NULL)
1586
 if(transaction == NULL)
1587
  {
1587
 {
1588
    /* send the message */
1588
 /* send the message */
1589
    init_fusd_msg(&fusd_msg);
1589
 init_fusd_msg(&fusd_msg);
1590
    fusd_msg.subcmd = FUSD_MMAP;
1590
 fusd_msg.subcmd = FUSD_MMAP;
1591
    fusd_msg.parm.fops_msg.offset = vma->vm_pgoff << PAGE_SHIFT;
1591
 fusd_msg.parm.fops_msg.offset = vma->vm_pgoff << PAGE_SHIFT;
1592
    fusd_msg.parm.fops_msg.flags = vma->vm_flags;
1592
 fusd_msg.parm.fops_msg.flags = vma->vm_flags;
1593
    fusd_msg.parm.fops_msg.length = vma->vm_end - vma->vm_start;
1593
 fusd_msg.parm.fops_msg.length = vma->vm_end - vma->vm_start;
1594
    
1594
1595
    /* send message to userspace */
1595
 /* send message to userspace */
1596
    if ((retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction)) < 0)
1596
 if ((retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction)) < 0)
1597
      goto done;
1597
 goto done;
1598
  }
1598
 }
1599
  
1599
1600
  /* and wait for the reply */
1600
 /* and wait for the reply */
1601
  /* todo: store and retrieve the transid from the interrupted messsage */
1601
 /* todo: store and retrieve the transid from the interrupted messsage */
1602
  retval = fusd_fops_call_wait(fusd_file, &reply, transaction);
1602
 retval = fusd_fops_call_wait(fusd_file, &reply, transaction);
1603
  
1603
1604
  mmap_instance = 
1604
 mmap_instance =
1605
    (struct fusd_mmap_instance*) KMALLOC(sizeof(struct fusd_mmap_instance), GFP_KERNEL);
1605
 (struct fusd_mmap_instance*) KMALLOC(sizeof(struct fusd_mmap_instance), GFP_KERNEL);
1606
  // todo: free this thing at some point
1606
 // todo: free this thing at some point
1607
  
1607
1608
  mmap_instance->fusd_dev = fusd_dev;
1608
 mmap_instance->fusd_dev = fusd_dev;
1609
  mmap_instance->fusd_file = fusd_file;
1609
 mmap_instance->fusd_file = fusd_file;
1610
  mmap_instance->addr = reply->parm.fops_msg.arg;
1610
 mmap_instance->addr = reply->parm.fops_msg.arg;
1611
  mmap_instance->size = reply->parm.fops_msg.length;
1611
 mmap_instance->size = reply->parm.fops_msg.length;
1612
  atomic_set(&mmap_instance->refcount, 0);
1612
 atomic_set(&mmap_instance->refcount, 0);
1613
  
1613
1614
  retval = reply->parm.fops_msg.retval;
1614
 retval = reply->parm.fops_msg.retval;
1615
  
1615
1616
  vma->vm_private_data = mmap_instance;
1616
 vma->vm_private_data = mmap_instance;
1617
  vma->vm_ops = &fusd_remap_vm_ops;
1617
 vma->vm_ops = &fusd_remap_vm_ops;
1618
  vma->vm_flags |= VM_RESERVED;
1618
 vma->vm_flags |= VM_RESERVED;
1619
  
1619
1620
  fusd_client_mm_open(vma);
1620
 fusd_client_mm_open(vma);
1621
  
1621
1622
 done:
1622
 done:
1623
  free_fusd_msg(&reply);
1623
 free_fusd_msg(&reply);
1624
  UNLOCK_FUSD_FILE(fusd_file);
1624
 UNLOCK_FUSD_FILE(fusd_file);
1625
  return retval;
1625
 return retval;
1626
1626
1627
 invalid_file:
1627
 invalid_file:
1628
 invalid_dev:
1628
 invalid_dev:
1629
  RDEBUG(3, "got a mmap on client file from pid %d, driver has disappeared",
1629
 RDEBUG(3, "got a mmap on client file from pid %d, driver has disappeared",
1630
	 current->pid);
1630
 current->pid);
1631
  return -EPIPE;
1631
 return -EPIPE;
1632
}
1632
}
1633
1633
1634
static struct page* fusd_client_nopage(struct vm_area_struct* vma, unsigned long address,
1634
static struct page* fusd_client_nopage(struct vm_area_struct* vma, unsigned long address,
1635
                                int* type)
1635
 int* type)
1636
{
1636
{
1637
  struct fusd_mmap_instance* mmap_instance = (struct fusd_mmap_instance*) vma->vm_private_data;
1637
 struct fusd_mmap_instance* mmap_instance = (struct fusd_mmap_instance*) vma->vm_private_data;
1638
  unsigned long offset;
1638
 unsigned long offset;
1639
  struct page *page = NOPAGE_SIGBUS;
1639
 struct page *page = NOPAGE_SIGBUS;
1640
  int result;
1640
 int result;
1641
  offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
1641
 offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
1642
  // todo: worry about size
1642
 // todo: worry about size
1643
  if(offset > mmap_instance->size)
1643
 if(offset > mmap_instance->size)
1644
    goto out;
1644
 goto out;
1645
  
1645
1646
  down_read(&mmap_instance->fusd_dev->task->mm->mmap_sem);
1646
 down_read(&mmap_instance->fusd_dev->task->mm->mmap_sem);
1647
  result = get_user_pages(mmap_instance->fusd_dev->task, mmap_instance->fusd_dev->task->mm, mmap_instance->addr + offset, 1, 1, 0, &page, NULL);
1647
 result = get_user_pages(mmap_instance->fusd_dev->task, mmap_instance->fusd_dev->task->mm, mmap_instance->addr + offset, 1, 1, 0, &page, NULL);
1648
  up_read(&mmap_instance->fusd_dev->task->mm->mmap_sem);
1648
 up_read(&mmap_instance->fusd_dev->task->mm->mmap_sem);
1649
  
1649
1650
  
1650
1651
  if(PageAnon(page))
1651
 if(PageAnon(page))
1652
  {
1652
 {
1653
    RDEBUG(2, "Cannot mmap anonymous pages. Be sure to allocate your shared buffer with MAP_SHARED | MAP_ANONYMOUS");
1653
 RDEBUG(2, "Cannot mmap anonymous pages. Be sure to allocate your shared buffer with MAP_SHARED | MAP_ANONYMOUS");
1654
    return NOPAGE_SIGBUS;
1654
 return NOPAGE_SIGBUS;
1655
  }
1655
 }
1656
  
1656
1657
  if(result > 0)
1657
 if(result > 0)
1658
  {
1658
 {
1659
    get_page(page);
1659
 get_page(page);
1660
    if (type)
1660
 if (type)
1661
      *type = VM_FAULT_MINOR;
1661
 *type = VM_FAULT_MINOR;
1662
  }
1662
 }
1663
out:
1663
out:
1664
  return page;
1664
 return page;
1665
1665
1666
1666
1667
}
1667
}
Lines 1671-1778 Link Here
1671
 * The design of poll for clients is a bit subtle.
1671
 * The design of poll for clients is a bit subtle.
1672
 *
1672
 *
1673
 * We don't want the select() call itself to block, so we keep a cache
1673
 * We don't want the select() call itself to block, so we keep a cache
1674
 * of the most recently known state supplied by the driver.  The cache
1674
 * of the most recently known state supplied by the driver. The cache
1675
 * is initialized to 0 (meaning: nothing readable/writable).
1675
 * is initialized to 0 (meaning: nothing readable/writable).
1676
 *
1676
 *
1677
 * When a poll comes in, we do a non-blocking (!) dispatch of a
1677
 * When a poll comes in, we do a non-blocking (!) dispatch of a
1678
 * command telling the driver "This is the state we have cached, reply
1678
 * command telling the driver "This is the state we have cached, reply
1679
 * to this call when the state changes.", and then immediately return
1679
 * to this call when the state changes.", and then immediately return
1680
 * the cached state.  We tell the kernel's select to sleep on our
1680
 * the cached state. We tell the kernel's select to sleep on our
1681
 * poll_wait wait queue.
1681
 * poll_wait wait queue.
1682
 *
1682
 *
1683
 * When the driver replies, we update our cached info and wake up the
1683
 * When the driver replies, we update our cached info and wake up the
1684
 * wait queue.  Waking up the wait queue will most likely immediately
1684
 * wait queue. Waking up the wait queue will most likely immediately
1685
 * effect a poll again, in which case we will reply whatever we just
1685
 * effect a poll again, in which case we will reply whatever we just
1686
 * cached from the driver.
1686
 * cached from the driver.
1687
 * 
1687
 *
1688
 */
1688
 */
1689
STATIC unsigned int fusd_client_poll(struct file *file, poll_table *wait)
1689
STATIC unsigned int fusd_client_poll(struct file *file, poll_table *wait)
1690
{
1690
{
1691
  fusd_dev_t *fusd_dev;
1691
 fusd_dev_t *fusd_dev;
1692
  fusd_file_t *fusd_file;
1692
 fusd_file_t *fusd_file;
1693
  int kernel_bits = 0;
1693
 int kernel_bits = 0;
1694
  int send_poll = 0;
1694
 int send_poll = 0;
1695
1695
1696
  GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev);
1696
 GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev);
1697
  LOCK_FUSD_FILE(fusd_file);
1697
 LOCK_FUSD_FILE(fusd_file);
1698
  LOCK_FUSD_DEV(fusd_dev);
1698
 LOCK_FUSD_DEV(fusd_dev);
1699
1699
1700
  RDEBUG(3, "got a select on /dev/%s (owned by pid %d) from pid %d, cps=%d",
1700
 RDEBUG(3, "got a select on /dev/%s (owned by pid %d) from pid %d, cps=%d",
1701
	 NAME(fusd_dev), fusd_dev->pid, current->pid,
1701
 NAME(fusd_dev), fusd_dev->pid, current->pid,
1702
	 fusd_file->cached_poll_state);
1702
 fusd_file->cached_poll_state);
1703
1703
1704
  poll_wait(file, &fusd_file->poll_wait, wait);
1704
 poll_wait(file, &fusd_file->poll_wait, wait);
1705
1705
1706
  /*
1706
 /*
1707
   * If our currently cached poll state is not the same as the
1707
 * If our currently cached poll state is not the same as the
1708
   * most-recently-sent polldiff request, then, dispatch a new
1708
 * most-recently-sent polldiff request, then, dispatch a new
1709
   * request.  (We DO NOT wait for a reply, but just dispatch the
1709
 * request. (We DO NOT wait for a reply, but just dispatch the
1710
   * request).
1710
 * request).
1711
   *
1711
 *
1712
   * Also, don't send a new polldiff if the most recent one resulted
1712
 * Also, don't send a new polldiff if the most recent one resulted
1713
   * in an error.
1713
 * in an error.
1714
   */
1714
 */
1715
  if (fusd_file->last_poll_sent != fusd_file->cached_poll_state &&
1715
 if (fusd_file->last_poll_sent != fusd_file->cached_poll_state &&
1716
      fusd_file->cached_poll_state >= 0) {
1716
 fusd_file->cached_poll_state >= 0) {
1717
    RDEBUG(3, "sending polldiff request because lps=%d, cps=%d",
1717
 RDEBUG(3, "sending polldiff request because lps=%d, cps=%d",
1718
	   fusd_file->last_poll_sent, fusd_file->cached_poll_state);
1718
 fusd_file->last_poll_sent, fusd_file->cached_poll_state);
1719
    send_poll = 1;
1719
 send_poll = 1;
1720
    fusd_file->last_poll_sent = fusd_file->cached_poll_state;
1720
 fusd_file->last_poll_sent = fusd_file->cached_poll_state;
1721
  }
1721
 }
1722
1722
1723
  /* compute what to return for the state we had cached, converting to
1723
 /* compute what to return for the state we had cached, converting to
1724
   * bits that have meaning to the kernel */
1724
 * bits that have meaning to the kernel */
1725
  if (fusd_file->cached_poll_state > 0) {
1725
 if (fusd_file->cached_poll_state > 0) {
1726
    if (fusd_file->cached_poll_state & FUSD_NOTIFY_INPUT)
1726
 if (fusd_file->cached_poll_state & FUSD_NOTIFY_INPUT)
1727
      kernel_bits |= POLLIN;
1727
 kernel_bits |= POLLIN;
1728
    if (fusd_file->cached_poll_state & FUSD_NOTIFY_OUTPUT)
1728
 if (fusd_file->cached_poll_state & FUSD_NOTIFY_OUTPUT)
1729
      kernel_bits |= POLLOUT;
1729
 kernel_bits |= POLLOUT;
1730
    if (fusd_file->cached_poll_state & FUSD_NOTIFY_EXCEPT)
1730
 if (fusd_file->cached_poll_state & FUSD_NOTIFY_EXCEPT)
1731
      kernel_bits |= POLLPRI;
1731
 kernel_bits |= POLLPRI;
1732
  }
1732
 }
1733
1733
1734
  /* Now that we've committed to sending the poll, etc., it should be
1734
 /* Now that we've committed to sending the poll, etc., it should be
1735
   * safe to unlock the device */
1735
 * safe to unlock the device */
1736
  UNLOCK_FUSD_DEV(fusd_dev);
1736
 UNLOCK_FUSD_DEV(fusd_dev);
1737
  UNLOCK_FUSD_FILE(fusd_file);
1737
 UNLOCK_FUSD_FILE(fusd_file);
1738
1738
1739
  if (send_poll) {
1739
 if (send_poll) {
1740
    fusd_msg_t fusd_msg;
1740
 fusd_msg_t fusd_msg;
1741
1741
1742
    init_fusd_msg(&fusd_msg);
1742
 init_fusd_msg(&fusd_msg);
1743
    fusd_msg.cmd = FUSD_FOPS_NONBLOCK;
1743
 fusd_msg.cmd = FUSD_FOPS_NONBLOCK;
1744
    fusd_msg.subcmd = FUSD_POLL_DIFF;
1744
 fusd_msg.subcmd = FUSD_POLL_DIFF;
1745
    fusd_msg.parm.fops_msg.cmd = fusd_file->cached_poll_state;
1745
 fusd_msg.parm.fops_msg.cmd = fusd_file->cached_poll_state;
1746
    if (fusd_fops_call_send(fusd_file, &fusd_msg, NULL) < 0) {
1746
 if (fusd_fops_call_send(fusd_file, &fusd_msg, NULL) < 0) {
1747
      /* If poll dispatched failed, set back to -1 so we try again.
1747
 /* If poll dispatched failed, set back to -1 so we try again.
1748
       * Not a race (I think), since sending an *extra* polldiff never
1748
 * Not a race (I think), since sending an *extra* polldiff never
1749
       * hurts anything. */
1749
 * hurts anything. */
1750
      fusd_file->last_poll_sent = -1;
1750
 fusd_file->last_poll_sent = -1;
1751
    }
1751
 }
1752
  }
1752
 }
1753
  return kernel_bits;
1753
 return kernel_bits;
1754
1754
1755
 zombie_dev:
1755
 zombie_dev:
1756
  /* might jump here from LOCK_FUSD_DEV */
1756
 /* might jump here from LOCK_FUSD_DEV */
1757
  UNLOCK_FUSD_FILE(fusd_file);
1757
 UNLOCK_FUSD_FILE(fusd_file);
1758
 invalid_dev:
1758
 invalid_dev:
1759
 invalid_file:
1759
 invalid_file:
1760
  RDEBUG(3, "got a select on client file from pid %d, driver has disappeared",
1760
 RDEBUG(3, "got a select on client file from pid %d, driver has disappeared",
1761
	 current->pid);
1761
 current->pid);
1762
  return POLLPRI;
1762
 return POLLPRI;
1763
}
1763
}
1764
1764
1765
1765
1766
1766
1767
STATIC struct file_operations fusd_client_fops = {
1767
STATIC struct file_operations fusd_client_fops = {
1768
  owner:    THIS_MODULE,
1768
 owner: THIS_MODULE,
1769
  open:     fusd_client_open,
1769
 open: fusd_client_open,
1770
  release:  fusd_client_release,
1770
 release: fusd_client_release,
1771
  read:     fusd_client_read,
1771
 read: fusd_client_read,
1772
  write:    fusd_client_write,
1772
 write: fusd_client_write,
1773
  ioctl:    fusd_client_ioctl,
1773
 ioctl: fusd_client_ioctl,
1774
  poll:     fusd_client_poll,
1774
 poll: fusd_client_poll,
1775
  mmap:     fusd_client_mmap
1775
 mmap: fusd_client_mmap
1776
};
1776
};
1777
1777
1778
1778
Lines 1783-2044 Link Here
1783
1783
1784
STATIC fusd_file_t *find_fusd_reply_file(fusd_dev_t *fusd_dev, fusd_msg_t *msg)
1784
STATIC fusd_file_t *find_fusd_reply_file(fusd_dev_t *fusd_dev, fusd_msg_t *msg)
1785
{
1785
{
1786
  /* first, try the hint */
1786
 /* first, try the hint */
1787
  int i = msg->parm.fops_msg.hint;
1787
 int i = msg->parm.fops_msg.hint;
1788
  if (i >= 0 &&
1788
 if (i >= 0 &&
1789
      i < fusd_dev->num_files &&
1789
 i < fusd_dev->num_files &&
1790
      fusd_dev->files[i] == msg->parm.fops_msg.fusd_file)
1790
 fusd_dev->files[i] == msg->parm.fops_msg.fusd_file)
1791
    {
1791
 {
1792
      RDEBUG(15, "find_fusd_reply_file: hint worked");
1792
 RDEBUG(15, "find_fusd_reply_file: hint worked");
1793
    } else {
1793
 } else {
1794
      /* hint didn't work, fall back to a search of the whole array */
1794
 /* hint didn't work, fall back to a search of the whole array */
1795
      i = find_fusd_file(fusd_dev, msg->parm.fops_msg.fusd_file);
1795
 i = find_fusd_file(fusd_dev, msg->parm.fops_msg.fusd_file);
1796
      RDEBUG(15, "find_fusd_reply_file: hint failed");
1796
 RDEBUG(15, "find_fusd_reply_file: hint failed");
1797
    }
1797
 }
1798
1798
1799
  /* we couldn't find anyone waiting for this message! */
1799
 /* we couldn't find anyone waiting for this message! */
1800
  if (i < 0) {
1800
 if (i < 0) {
1801
    return NULL;
1801
 return NULL;
1802
  } else {
1802
 } else {
1803
    return fusd_dev->files[i];
1803
 return fusd_dev->files[i];
1804
  }
1804
 }
1805
}
1805
}
1806
1806
1807
1807
1808
/* Process an incoming reply to a message dispatched by
1808
/* Process an incoming reply to a message dispatched by
1809
 * fusd_fops_call.  Called by fusd_write when a driver writes to
1809
 * fusd_fops_call. Called by fusd_write when a driver writes to
1810
 * /dev/fusd. */
1810
 * /dev/fusd. */
1811
STATIC int fusd_fops_reply(fusd_dev_t *fusd_dev, fusd_msg_t *msg)
1811
STATIC int fusd_fops_reply(fusd_dev_t *fusd_dev, fusd_msg_t *msg)
1812
{
1812
{
1813
  fusd_file_t *fusd_file;
1813
 fusd_file_t *fusd_file;
1814
  struct fusd_transaction *transaction;
1814
 struct fusd_transaction *transaction;
1815
1815
1816
  /* figure out the index of the file we are replying to.  usually
1816
 /* figure out the index of the file we are replying to. usually
1817
   * very fast (uses a hint) */
1817
 * very fast (uses a hint) */
1818
  if ((fusd_file = find_fusd_reply_file(fusd_dev, msg)) == NULL) {
1818
 if ((fusd_file = find_fusd_reply_file(fusd_dev, msg)) == NULL) {
1819
    RDEBUG(2, "fusd_fops_reply: got a reply on /dev/%s with no connection",
1819
 RDEBUG(2, "fusd_fops_reply: got a reply on /dev/%s with no connection",
1820
	   NAME(fusd_dev));
1820
 NAME(fusd_dev));
1821
    goto discard;
1821
 goto discard;
1822
  }
1822
 }
1823
1823
1824
  /* make sure this is not an old reply going to an old instance that's gone */
1824
 /* make sure this is not an old reply going to an old instance that's gone */
1825
	/* todo: kor fix this */
1825
 /* todo: kor fix this */
1826
/*
1826
/*
1827
  if (fusd_file->fusd_dev_version != fusd_dev->version ||
1827
 if (fusd_file->fusd_dev_version != fusd_dev->version ||
1828
      msg->parm.fops_msg.transid != fusd_file->transid_outstanding) {
1828
 msg->parm.fops_msg.transid != fusd_file->transid_outstanding) {
1829
    RDEBUG(2, "fusd_fops_reply: got an old message, discarding");
1829
 RDEBUG(2, "fusd_fops_reply: got an old message, discarding");
1830
    goto discard;
1830
 goto discard;
1831
  }*/
1831
 }*/
1832
  
1832
1833
  transaction = fusd_find_transaction(fusd_file, msg->parm.fops_msg.transid);
1833
 transaction = fusd_find_transaction(fusd_file, msg->parm.fops_msg.transid);
1834
	if(transaction == NULL)
1834
 if(transaction == NULL)
1835
	{
1835
 {
1836
		RDEBUG(2, "fusd_fops_reply: No transaction found with transid %ld", msg->parm.fops_msg.transid);
1836
 RDEBUG(2, "fusd_fops_reply: No transaction found with transid %ld", msg->parm.fops_msg.transid);
1837
		goto discard;
1837
 goto discard;
1838
	}
1838
 }
1839
	
1839
1840
  RDEBUG(10, "fusd_fops_reply: /dev/%s completed transid %ld (retval %d)",
1840
 RDEBUG(10, "fusd_fops_reply: /dev/%s completed transid %ld (retval %d)",
1841
	 NAME(fusd_dev), msg->parm.fops_msg.transid,
1841
 NAME(fusd_dev), msg->parm.fops_msg.transid,
1842
	 (int) msg->parm.fops_msg.retval);
1842
 (int) msg->parm.fops_msg.retval);
1843
1843
1844
  transaction->msg_in = msg;
1844
 transaction->msg_in = msg;
1845
	mb();
1845
 mb();
1846
1846
1847
  WAKE_UP_INTERRUPTIBLE_SYNC(&fusd_file->file_wait);
1847
 WAKE_UP_INTERRUPTIBLE_SYNC(&fusd_file->file_wait);
1848
1848
1849
  return 0;
1849
 return 0;
1850
1850
1851
 discard:
1851
 discard:
1852
  if (msg->subcmd == FUSD_OPEN && msg->parm.fops_msg.retval == 0) {
1852
 if (msg->subcmd == FUSD_OPEN && msg->parm.fops_msg.retval == 0) {
1853
    fusd_forge_close(msg, fusd_dev);
1853
 fusd_forge_close(msg, fusd_dev);
1854
    return 0;
1854
 return 0;
1855
  } else {
1855
 } else {
1856
    return -EPIPE;
1856
 return -EPIPE;
1857
  }
1857
 }
1858
}
1858
}
1859
1859
1860
1860
1861
/* special function to process responses to POLL_DIFF */
1861
/* special function to process responses to POLL_DIFF */
1862
STATIC int fusd_polldiff_reply(fusd_dev_t *fusd_dev, fusd_msg_t *msg)
1862
STATIC int fusd_polldiff_reply(fusd_dev_t *fusd_dev, fusd_msg_t *msg)
1863
{
1863
{
1864
  fusd_file_t *fusd_file;
1864
 fusd_file_t *fusd_file;
1865
1865
1866
  /* figure out the index of the file we are replying to.  usually
1866
 /* figure out the index of the file we are replying to. usually
1867
   * very fast (uses a hint) */
1867
 * very fast (uses a hint) */
1868
  if ((fusd_file = find_fusd_reply_file(fusd_dev, msg)) == NULL)
1868
 if ((fusd_file = find_fusd_reply_file(fusd_dev, msg)) == NULL)
1869
    return -EPIPE;
1869
 return -EPIPE;
1870
1870
1871
  /* record the poll state returned.  convert all negative retvals to -1. */
1871
 /* record the poll state returned. convert all negative retvals to -1. */
1872
  if ((fusd_file->cached_poll_state = msg->parm.fops_msg.retval) < 0)
1872
 if ((fusd_file->cached_poll_state = msg->parm.fops_msg.retval) < 0)
1873
    fusd_file->cached_poll_state = -1;
1873
 fusd_file->cached_poll_state = -1;
1874
1874
1875
  RDEBUG(3, "got updated poll state from /dev/%s driver: %d", NAME(fusd_dev),
1875
 RDEBUG(3, "got updated poll state from /dev/%s driver: %d", NAME(fusd_dev),
1876
	 fusd_file->cached_poll_state);
1876
 fusd_file->cached_poll_state);
1877
1877
1878
  /* since the client has returned the polldiff we sent, set
1878
 /* since the client has returned the polldiff we sent, set
1879
   * last_poll_sent to -1, so that we'll send a polldiff request on
1879
 * last_poll_sent to -1, so that we'll send a polldiff request on
1880
   * the next select. */
1880
 * the next select. */
1881
  fusd_file->last_poll_sent = -1;
1881
 fusd_file->last_poll_sent = -1;
1882
1882
1883
  /* wake up select's queue so that a new polldiff is generated */
1883
 /* wake up select's queue so that a new polldiff is generated */
1884
  wake_up_interruptible(&fusd_file->poll_wait);
1884
 wake_up_interruptible(&fusd_file->poll_wait);
1885
1885
1886
  return 0;
1886
 return 0;
1887
}
1887
}
1888
1888
1889
STATIC int fusd_register_device(fusd_dev_t *fusd_dev,
1889
STATIC int fusd_register_device(fusd_dev_t *fusd_dev,
1890
				register_msg_t register_msg)
1890
 register_msg_t register_msg)
1891
{
1891
{
1892
  int error = 0;
1892
 int error = 0;
1893
  struct list_head *tmp;
1893
 struct list_head *tmp;
1894
  int dev_id;
1894
 int dev_id;
1895
1895
1896
  /* make sure args are valid */
1896
 /* make sure args are valid */
1897
  if (fusd_dev == NULL) {
1897
 if (fusd_dev == NULL) {
1898
    RDEBUG(0, "fusd_register_device: bug in arguments!");
1898
 RDEBUG(0, "fusd_register_device: bug in arguments!");
1899
    return -EINVAL;
1899
 return -EINVAL;
1900
  }
1900
 }
1901
1901
1902
  /* user can only register one device per instance */
1902
 /* user can only register one device per instance */
1903
//  if (fusd_dev->handle != 0)
1903
// if (fusd_dev->handle != 0)
1904
//    return -EBUSY;
1904
// return -EBUSY;
1905
1905
1906
  register_msg.name[FUSD_MAX_NAME_LENGTH] = '\0';
1906
 register_msg.name[FUSD_MAX_NAME_LENGTH] = '\0';
1907
1907
1908
  /* make sure that there isn't already a device by this name */
1908
 /* make sure that there isn't already a device by this name */
1909
  down(&fusd_devlist_sem);
1909
 down(&fusd_devlist_sem);
1910
  list_for_each(tmp, &fusd_devlist_head) {
1910
 list_for_each(tmp, &fusd_devlist_head) {
1911
    fusd_dev_t *d = list_entry(tmp, fusd_dev_t, devlist);
1911
 fusd_dev_t *d = list_entry(tmp, fusd_dev_t, devlist);
1912
1912
1913
    if (d && d->name && !d->zombie && !strcmp(d->name, register_msg.name)) {
1913
 if (d && d->name && !d->zombie && !strcmp(d->name, register_msg.name)) {
1914
      error = -EEXIST;
1914
 error = -EEXIST;
1915
      break;
1915
 break;
1916
    }
1916
 }
1917
  }
1917
 }
1918
  up(&fusd_devlist_sem);
1918
 up(&fusd_devlist_sem);
1919
1919
1920
  if (error)
1920
 if (error)
1921
    return error;
1921
 return error;
1922
1922
1923
1923
1924
  /* allocate memory for the name, and copy */
1924
 /* allocate memory for the name, and copy */
1925
  if ((fusd_dev->name = KMALLOC(strlen(register_msg.name)+1, GFP_KERNEL)) == NULL) {
1925
 if ((fusd_dev->name = KMALLOC(strlen(register_msg.name)+1, GFP_KERNEL)) == NULL) {
1926
     RDEBUG(1, "yikes!  kernel can't allocate memory");
1926
 RDEBUG(1, "yikes! kernel can't allocate memory");
1927
     return -ENOMEM;
1927
 return -ENOMEM;
1928
  }
1928
 }
1929
	
1929
1930
  strcpy(fusd_dev->name, register_msg.name);
1930
 strcpy(fusd_dev->name, register_msg.name);
1931
1931
1932
  /* allocate memory for the class name, and copy */
1932
 /* allocate memory for the class name, and copy */
1933
  if ((fusd_dev->class_name = KMALLOC(strlen(register_msg.clazz)+1, GFP_KERNEL)) == NULL) {
1933
 if ((fusd_dev->class_name = KMALLOC(strlen(register_msg.clazz)+1, GFP_KERNEL)) == NULL) {
1934
     RDEBUG(1, "yikes!  kernel can't allocate memory");
1934
 RDEBUG(1, "yikes! kernel can't allocate memory");
1935
     return -ENOMEM;
1935
 return -ENOMEM;
1936
  }
1936
 }
1937
	
1937
1938
	strcpy(fusd_dev->class_name, register_msg.clazz);
1938
 strcpy(fusd_dev->class_name, register_msg.clazz);
1939
	
1939
1940
  /* allocate memory for the class name, and copy */
1940
 /* allocate memory for the class name, and copy */
1941
  if ((fusd_dev->dev_name = KMALLOC(strlen(register_msg.devname)+1, GFP_KERNEL)) == NULL) {
1941
 if ((fusd_dev->dev_name = KMALLOC(strlen(register_msg.devname)+1, GFP_KERNEL)) == NULL) {
1942
     RDEBUG(1, "yikes!  kernel can't allocate memory");
1942
 RDEBUG(1, "yikes! kernel can't allocate memory");
1943
     return -ENOMEM;
1943
 return -ENOMEM;
1944
  }
1944
 }
1945
	
1945
1946
	strcpy(fusd_dev->dev_name, register_msg.devname);
1946
 strcpy(fusd_dev->dev_name, register_msg.devname);
1947
1947
1948
	dev_id = 0;
1948
 dev_id = 0;
1949
1949
1950
	if((error = alloc_chrdev_region(&dev_id, 0, 1, fusd_dev->name)) < 0)
1950
 if((error = alloc_chrdev_region(&dev_id, 0, 1, fusd_dev->name)) < 0)
1951
	{
1951
 {
1952
		printk("alloc_chrdev_region failed status: %d\n", error);
1952
 printk("alloc_chrdev_region failed status: %d\n", error);
1953
		goto register_failed;
1953
 goto register_failed;
1954
	}
1954
 }
1955
1955
1956
	fusd_dev->dev_id = dev_id;
1956
 fusd_dev->dev_id = dev_id;
1957
1957
1958
	#ifdef CONFIG_DEVFS_FS
1958
 #ifdef CONFIG_DEVFS_FS
1959
	if((error = devfs_mk_cdev(dev_id, S_IFCHR | register_msg.mode, fusd_dev->name)) < 0)
1959
 if((error = devfs_mk_cdev(dev_id, S_IFCHR | register_msg.mode, fusd_dev->name)) < 0)
1960
	{
1960
 {
1961
		printk("devfs_mk_cdev failed status: %d\n", error);
1961
 printk("devfs_mk_cdev failed status: %d\n", error);
1962
		goto register_failed2;
1962
 goto register_failed2;
1963
	}
1963
 }
1964
	#endif
1964
 #endif
1965
1965
1966
	fusd_dev->handle = cdev_alloc();
1966
 fusd_dev->handle = cdev_alloc();
1967
	if(fusd_dev->handle == NULL)
1967
 if(fusd_dev->handle == NULL)
1968
	{
1968
 {
1969
		error = -ENOMEM;
1969
 error = -ENOMEM;
1970
		goto register_failed3;
1970
 goto register_failed3;
1971
	}
1971
 }
1972
1972
1973
	fusd_dev->handle->owner = THIS_MODULE;
1973
 fusd_dev->handle->owner = THIS_MODULE;
1974
	fusd_dev->handle->ops = &fusd_client_fops;
1974
 fusd_dev->handle->ops = &fusd_client_fops;
1975
1975
1976
	kobject_set_name(&fusd_dev->handle->kobj, fusd_dev->name);
1976
 kobject_set_name(&fusd_dev->handle->kobj, fusd_dev->name);
1977
1977
1978
	if((error = cdev_add(fusd_dev->handle, dev_id, 1)) < 0)
1978
 if((error = cdev_add(fusd_dev->handle, dev_id, 1)) < 0)
1979
	{
1979
 {
1980
		printk("cdev_add failed status: %d\n", error);
1980
 printk("cdev_add failed status: %d\n", error);
1981
		kobject_put(&fusd_dev->handle->kobj);
1981
 kobject_put(&fusd_dev->handle->kobj);
1982
		goto register_failed3;
1982
 goto register_failed3;
1983
	}
1983
 }
1984
1984
1985
	// Hack to add my class to the sound class
1985
 // Hack to add my class to the sound class
1986
	if(strcmp("sound", register_msg.clazz) == 0)
1986
 if(strcmp("sound", register_msg.clazz) == 0)
1987
	{
1987
 {
1988
		fusd_dev->clazz = sound_class;
1988
 fusd_dev->clazz = sound_class;
1989
		fusd_dev->owns_class = 0;
1989
 fusd_dev->owns_class = 0;
1990
	}
1990
 }
1991
	else
1991
 else
1992
	{
1992
 {
1993
		fusd_dev->clazz = class_create(THIS_MODULE, fusd_dev->class_name);
1993
 fusd_dev->clazz = class_create(THIS_MODULE, fusd_dev->class_name);
1994
		if(IS_ERR(fusd_dev->clazz))
1994
 if(IS_ERR(fusd_dev->clazz))
1995
		{
1995
 {
1996
			error = PTR_ERR(fusd_dev->clazz);
1996
 error = PTR_ERR(fusd_dev->clazz);
1997
			goto register_failed4;
1997
 goto register_failed4;
1998
		}
1998
 }
1999
		fusd_dev->owns_class = 1;
1999
 fusd_dev->owns_class = 1;
2000
	}
2000
 }
2001
	
2001
2002
	fusd_dev->class_device = CLASS_DEVICE_CREATE(fusd_dev->clazz, NULL, fusd_dev->dev_id, NULL, fusd_dev->dev_name);
2002
 fusd_dev->class_device = CLASS_DEVICE_CREATE(fusd_dev->clazz, NULL, fusd_dev->dev_id, NULL, fusd_dev->dev_name);
2003
	if(fusd_dev->class_device == NULL)
2003
 if(fusd_dev->class_device == NULL)
2004
	{
2004
 {
2005
		error = PTR_ERR(fusd_dev->class_device);
2005
 error = PTR_ERR(fusd_dev->class_device);
2006
		printk("class_device_create failed status: %d\n", error);
2006
 printk("class_device_create failed status: %d\n", error);
2007
		goto register_failed5;
2007
 goto register_failed5;
2008
	}
2008
 }
2009
	
2009
2010
	/* make sure the registration was successful */
2010
 /* make sure the registration was successful */
2011
  /*
2011
 /*
2012
  if (fusd_dev->handle == 0) {
2012
 if (fusd_dev->handle == 0) {
2013
    error = -EIO;
2013
 error = -EIO;
2014
    goto register_failed;
2014
 goto register_failed;
2015
  }
2015
 }
2016
  */
2016
 */
2017
2017
2018
  /* remember the user's private data so we can pass it back later */
2018
 /* remember the user's private data so we can pass it back later */
2019
  fusd_dev->private_data = register_msg.device_info;
2019
 fusd_dev->private_data = register_msg.device_info;
2020
2020
2021
  /* everything ok */
2021
 /* everything ok */
2022
  fusd_dev->version = atomic_inc_and_ret(&last_version);
2022
 fusd_dev->version = atomic_inc_and_ret(&last_version);
2023
  RDEBUG(3, "pid %d registered /dev/%s v%ld", fusd_dev->pid, NAME(fusd_dev),
2023
 RDEBUG(3, "pid %d registered /dev/%s v%ld", fusd_dev->pid, NAME(fusd_dev),
2024
	 fusd_dev->version);
2024
 fusd_dev->version);
2025
  wake_up_interruptible(&new_device_wait);
2025
 wake_up_interruptible(&new_device_wait);
2026
  return 0;
2026
 return 0;
2027
2027
2028
register_failed5:
2028
register_failed5:
2029
	class_destroy(fusd_dev->clazz);
2029
 class_destroy(fusd_dev->clazz);
2030
register_failed4:
2030
register_failed4:
2031
	cdev_del(fusd_dev->handle);
2031
 cdev_del(fusd_dev->handle);
2032
register_failed3:
2032
register_failed3:
2033
#ifdef CONFIG_DEVFS_FS
2033
#ifdef CONFIG_DEVFS_FS
2034
	devfs_remove(fusd_dev->name);
2034
 devfs_remove(fusd_dev->name);
2035
#endif
2035
#endif
2036
register_failed2:
2036
/*register_failed2:*/
2037
	unregister_chrdev_region(dev_id, 1);
2037
 unregister_chrdev_region(dev_id, 1);
2038
register_failed:
2038
register_failed:
2039
  KFREE(fusd_dev->name);
2039
 KFREE(fusd_dev->name);
2040
  fusd_dev->name = NULL;
2040
 fusd_dev->name = NULL;
2041
  return error;
2041
 return error;
2042
}
2042
}
2043
2043
2044
2044
Lines 2050-2153 Link Here
2050
/* open() called on /dev/fusd itself */
2050
/* open() called on /dev/fusd itself */
2051
STATIC int fusd_open(struct inode *inode, struct file *file)
2051
STATIC int fusd_open(struct inode *inode, struct file *file)
2052
{
2052
{
2053
  fusd_dev_t *fusd_dev = NULL;
2053
 fusd_dev_t *fusd_dev = NULL;
2054
  fusd_file_t **file_array = NULL;
2054
 fusd_file_t **file_array = NULL;
2055
2055
2056
  /* keep the module from being unloaded during initialization! */
2056
 /* keep the module from being unloaded during initialization! */
2057
  //MOD_INC_USE_COUNT;
2057
 //MOD_INC_USE_COUNT;
2058
2058
2059
  /* allocate memory for the device state */
2059
 /* allocate memory for the device state */
2060
  if ((fusd_dev = KMALLOC(sizeof(fusd_dev_t), GFP_KERNEL)) == NULL)
2060
 if ((fusd_dev = KMALLOC(sizeof(fusd_dev_t), GFP_KERNEL)) == NULL)
2061
    goto dev_malloc_failed;
2061
 goto dev_malloc_failed;
2062
  memset(fusd_dev, 0, sizeof(fusd_dev_t));
2062
 memset(fusd_dev, 0, sizeof(fusd_dev_t));
2063
2063
2064
  if ((file_array = fusd_dev_adjsize(fusd_dev)) == NULL)
2064
 if ((file_array = fusd_dev_adjsize(fusd_dev)) == NULL)
2065
    goto file_malloc_failed;
2065
 goto file_malloc_failed;
2066
2066
2067
  init_waitqueue_head(&fusd_dev->dev_wait);
2067
 init_waitqueue_head(&fusd_dev->dev_wait);
2068
  init_MUTEX(&fusd_dev->dev_sem);
2068
 init_MUTEX(&fusd_dev->dev_sem);
2069
  fusd_dev->magic = FUSD_DEV_MAGIC;
2069
 fusd_dev->magic = FUSD_DEV_MAGIC;
2070
  fusd_dev->pid = current->pid;
2070
 fusd_dev->pid = current->pid;
2071
  fusd_dev->task = current;
2071
 fusd_dev->task = current;
2072
  file->private_data = fusd_dev;
2072
 file->private_data = fusd_dev;
2073
2073
2074
  /* add to the list of valid devices */
2074
 /* add to the list of valid devices */
2075
  down(&fusd_devlist_sem);
2075
 down(&fusd_devlist_sem);
2076
  list_add(&fusd_dev->devlist, &fusd_devlist_head);
2076
 list_add(&fusd_dev->devlist, &fusd_devlist_head);
2077
  up(&fusd_devlist_sem);
2077
 up(&fusd_devlist_sem);
2078
2078
2079
  RDEBUG(3, "pid %d opened /dev/fusd", fusd_dev->pid);
2079
 RDEBUG(3, "pid %d opened /dev/fusd", fusd_dev->pid);
2080
  return 0;
2080
 return 0;
2081
2081
2082
 file_malloc_failed:
2082
 file_malloc_failed:
2083
  KFREE(fusd_dev);
2083
 KFREE(fusd_dev);
2084
 dev_malloc_failed:
2084
 dev_malloc_failed:
2085
  RDEBUG(1, "out of memory in fusd_open!");
2085
 RDEBUG(1, "out of memory in fusd_open!");
2086
  //MOD_DEC_USE_COUNT;
2086
 //MOD_DEC_USE_COUNT;
2087
  return -ENOMEM;
2087
 return -ENOMEM;
2088
}
2088
}
2089
2089
2090
2090
2091
/* close() called on /dev/fusd itself.  destroy the device that
2091
/* close() called on /dev/fusd itself. destroy the device that
2092
 * was registered by it, if any. */
2092
 * was registered by it, if any. */
2093
STATIC int fusd_release(struct inode *inode, struct file *file)
2093
STATIC int fusd_release(struct inode *inode, struct file *file)
2094
{
2094
{
2095
  fusd_dev_t *fusd_dev;
2095
 fusd_dev_t *fusd_dev;
2096
2096
2097
  GET_FUSD_DEV(file->private_data, fusd_dev);
2097
 GET_FUSD_DEV(file->private_data, fusd_dev);
2098
  LOCK_FUSD_DEV(fusd_dev);
2098
 LOCK_FUSD_DEV(fusd_dev);
2099
2099
2100
  if (fusd_dev->pid != current->pid) {
2100
 if (fusd_dev->pid != current->pid) {
2101
    RDEBUG(2, "yikes!: when releasing device, pid mismatch");
2101
 RDEBUG(2, "yikes!: when releasing device, pid mismatch");
2102
  }
2102
 }
2103
2103
2104
  RDEBUG(3, "pid %d closing /dev/fusd", current->pid);
2104
 RDEBUG(3, "pid %d closing /dev/fusd", current->pid);
2105
2105
2106
#if 0
2106
#if 0
2107
  /* This delay is needed to exercise the openrace.c race condition,
2107
 /* This delay is needed to exercise the openrace.c race condition,
2108
   * i.e. testing to make sure that our open_in_progress stuff works */
2108
 * i.e. testing to make sure that our open_in_progress stuff works */
2109
  {
2109
 {
2110
    int target = jiffies + 10*HZ;
2110
 int target = jiffies + 10*HZ;
2111
2111
2112
    RDEBUG(1, "starting to wait");
2112
 RDEBUG(1, "starting to wait");
2113
    while (jiffies < target)
2113
 while (jiffies < target)
2114
      schedule();
2114
 schedule();
2115
    RDEBUG(1, "stopping wait");
2115
 RDEBUG(1, "stopping wait");
2116
  }
2116
 }
2117
#endif
2118
2119
	if(fusd_dev->handle)
2120
	{
2121
		class_device_destroy(fusd_dev->clazz, fusd_dev->dev_id);
2122
		if(fusd_dev->owns_class)
2123
		{
2124
			class_destroy(fusd_dev->clazz);
2125
		}
2126
		cdev_del(fusd_dev->handle);
2127
#ifdef CONFIG_DEVFS_FS
2128
  	devfs_remove(fusd_dev->name);
2129
#endif
2117
#endif
2130
		unregister_chrdev_region(fusd_dev->dev_id, 1);
2131
	}
2132
2118
2133
  /* mark the driver as being gone */
2119
 if(fusd_dev->handle)
2134
  zombify_dev(fusd_dev);
2120
 {
2121
 class_device_destroy(fusd_dev->clazz, fusd_dev->dev_id);
2122
 if(fusd_dev->owns_class)
2123
 {
2124
 class_destroy(fusd_dev->clazz);
2125
 }
2126
 cdev_del(fusd_dev->handle);
2127
#ifdef CONFIG_DEVFS_FS
2128
 devfs_remove(fusd_dev->name);
2129
#endif
2130
 unregister_chrdev_region(fusd_dev->dev_id, 1);
2131
 }
2135
2132
2136
  /* ...and possibly free it.  (Release lock if it hasn't been freed) */
2133
 /* mark the driver as being gone */
2137
  if (!maybe_free_fusd_dev(fusd_dev))
2134
 zombify_dev(fusd_dev);
2138
    UNLOCK_FUSD_DEV(fusd_dev);
2139
2135
2140
  /* notify fusd_status readers that there has been a change in the
2136
 /* ...and possibly free it. (Release lock if it hasn't been freed) */
2141
   * list of registered devices */
2137
 if (!maybe_free_fusd_dev(fusd_dev))
2142
  atomic_inc_and_ret(&last_version);
2138
 UNLOCK_FUSD_DEV(fusd_dev);
2143
  wake_up_interruptible(&new_device_wait);
2139
2140
 /* notify fusd_status readers that there has been a change in the
2141
 * list of registered devices */
2142
 atomic_inc_and_ret(&last_version);
2143
 wake_up_interruptible(&new_device_wait);
2144
2144
2145
  return 0;
2145
 return 0;
2146
2146
2147
 zombie_dev:
2147
 zombie_dev:
2148
 invalid_dev:
2148
 invalid_dev:
2149
  RDEBUG(1, "invalid device found in fusd_release!!");
2149
 RDEBUG(1, "invalid device found in fusd_release!!");
2150
  return -ENODEV;
2150
 return -ENODEV;
2151
}
2151
}
2152
2152
2153
2153
Lines 2156-2331 Link Here
2156
 * (i.e., writes to the /dev/fusd control channel.)
2156
 * (i.e., writes to the /dev/fusd control channel.)
2157
 */
2157
 */
2158
STATIC ssize_t fusd_process_write(struct file *file,
2158
STATIC ssize_t fusd_process_write(struct file *file,
2159
   const char *user_msg_buffer, size_t user_msg_len,
2159
 const char *user_msg_buffer, size_t user_msg_len,
2160
   const char *user_data_buffer, size_t user_data_len)
2160
 const char *user_data_buffer, size_t user_data_len)
2161
{
2161
{
2162
  fusd_dev_t *fusd_dev;
2162
 fusd_dev_t *fusd_dev;
2163
  fusd_msg_t *msg = NULL;
2163
 fusd_msg_t *msg = NULL;
2164
  int retval = 0;
2164
 int retval = 0;
2165
  int yield = 0;
2165
 int yield = 0;
2166
2166
2167
  GET_FUSD_DEV(file->private_data, fusd_dev);
2167
 GET_FUSD_DEV(file->private_data, fusd_dev);
2168
  LOCK_FUSD_DEV(fusd_dev);
2168
 LOCK_FUSD_DEV(fusd_dev);
2169
2169
2170
  /* get the header from userspace (first make sure there's enough data) */
2170
 /* get the header from userspace (first make sure there's enough data) */
2171
  if (user_msg_len != sizeof(fusd_msg_t)) {
2171
 if (user_msg_len != sizeof(fusd_msg_t)) {
2172
    RDEBUG(6, "control channel got bad write of %d bytes (wanted %d)",
2172
 RDEBUG(6, "control channel got bad write of %d bytes (wanted %d)",
2173
	   (int) user_msg_len, (int) sizeof(fusd_msg_t));
2173
 (int) user_msg_len, (int) sizeof(fusd_msg_t));
2174
    retval = -EINVAL;
2174
 retval = -EINVAL;
2175
    goto out_no_free;
2175
 goto out_no_free;
2176
  }
2176
 }
2177
  if ((msg = KMALLOC(sizeof(fusd_msg_t), GFP_KERNEL)) == NULL) {
2177
 if ((msg = KMALLOC(sizeof(fusd_msg_t), GFP_KERNEL)) == NULL) {
2178
    retval = -ENOMEM;
2178
 retval = -ENOMEM;
2179
    RDEBUG(1, "yikes!  kernel can't allocate memory");
2179
 RDEBUG(1, "yikes! kernel can't allocate memory");
2180
    goto out;
2180
 goto out;
2181
  }
2181
 }
2182
  memset(msg, 0, sizeof(fusd_msg_t));
2182
 memset(msg, 0, sizeof(fusd_msg_t));
2183
2183
2184
  if (copy_from_user(msg, user_msg_buffer, sizeof(fusd_msg_t))) {
2184
 if (copy_from_user(msg, user_msg_buffer, sizeof(fusd_msg_t))) {
2185
    retval = -EFAULT;
2185
 retval = -EFAULT;
2186
    goto out;
2186
 goto out;
2187
  }
2187
 }
2188
  msg->data = NULL; /* pointers from userspace have no meaning */
2188
 msg->data = NULL; /* pointers from userspace have no meaning */
2189
2189
2190
  /* check the magic number before acting on the message at all */
2190
 /* check the magic number before acting on the message at all */
2191
  if (msg->magic != FUSD_MSG_MAGIC) {
2191
 if (msg->magic != FUSD_MSG_MAGIC) {
2192
    RDEBUG(2, "got invalid magic number on /dev/fusd write from pid %d",
2192
 RDEBUG(2, "got invalid magic number on /dev/fusd write from pid %d",
2193
	   current->pid);
2193
 current->pid);
2194
    retval = -EIO;
2194
 retval = -EIO;
2195
    goto out;
2195
 goto out;
2196
  }
2196
 }
2197
2197
2198
  /* now get data portion of the message */
2198
 /* now get data portion of the message */
2199
  if (user_data_len < 0 || user_data_len > MAX_RW_SIZE) {
2199
 if (user_data_len < 0 || user_data_len > MAX_RW_SIZE) {
2200
    RDEBUG(2, "fusd_process_write: got invalid length %d", (int) user_data_len);
2200
 RDEBUG(2, "fusd_process_write: got invalid length %d", (int) user_data_len);
2201
    retval = -EINVAL;
2201
 retval = -EINVAL;
2202
    goto out;
2202
 goto out;
2203
  }
2203
 }
2204
  if (msg->datalen != user_data_len) {
2204
 if (msg->datalen != user_data_len) {
2205
    RDEBUG(2, "msg->datalen(%d) != user_data_len(%d), sigh!",
2205
 RDEBUG(2, "msg->datalen(%d) != user_data_len(%d), sigh!",
2206
	   msg->datalen, (int) user_data_len);
2206
 msg->datalen, (int) user_data_len);
2207
    retval = -EINVAL;
2207
 retval = -EINVAL;
2208
    goto out;
2208
 goto out;
2209
  }
2209
 }
2210
  if (user_data_len > 0) {
2210
 if (user_data_len > 0) {
2211
    if (user_data_buffer == NULL) {
2211
 if (user_data_buffer == NULL) {
2212
      RDEBUG(2, "msg->datalen and no data buffer, sigh!");
2212
 RDEBUG(2, "msg->datalen and no data buffer, sigh!");
2213
      retval = -EINVAL;
2213
 retval = -EINVAL;
2214
      goto out;
2214
 goto out;
2215
    }
2215
 }
2216
    if ((msg->data = VMALLOC(user_data_len)) == NULL) {
2216
 if ((msg->data = VMALLOC(user_data_len)) == NULL) {
2217
      retval = -ENOMEM;
2217
 retval = -ENOMEM;
2218
      RDEBUG(1, "yikes!  kernel can't allocate memory");
2218
 RDEBUG(1, "yikes! kernel can't allocate memory");
2219
      goto out;
2219
 goto out;
2220
    }
2220
 }
2221
    if (copy_from_user(msg->data, user_data_buffer, user_data_len)) {
2221
 if (copy_from_user(msg->data, user_data_buffer, user_data_len)) {
2222
      retval = -EFAULT;
2222
 retval = -EFAULT;
2223
      goto out;
2223
 goto out;
2224
    }
2224
 }
2225
  }
2225
 }
2226
2226
2227
  /* before device registration, the only command allowed is 'register'. */
2227
 /* before device registration, the only command allowed is 'register'. */
2228
  /*
2228
 /*
2229
  if (!fusd_dev->handle && msg->cmd != FUSD_REGISTER_DEVICE) {
2229
 if (!fusd_dev->handle && msg->cmd != FUSD_REGISTER_DEVICE) {
2230
    RDEBUG(2, "got a message other than 'register' on a new device!");
2230
 RDEBUG(2, "got a message other than 'register' on a new device!");
2231
    retval = -EINVAL;
2231
 retval = -EINVAL;
2232
    goto out;
2232
 goto out;
2233
  }
2233
 }
2234
  */
2234
 */
2235
2235
2236
  /* now dispatch the command to the appropriate handler */
2236
 /* now dispatch the command to the appropriate handler */
2237
  switch (msg->cmd) {
2237
 switch (msg->cmd) {
2238
  case FUSD_REGISTER_DEVICE:
2238
 case FUSD_REGISTER_DEVICE:
2239
    retval = fusd_register_device(fusd_dev, msg->parm.register_msg);
2239
 retval = fusd_register_device(fusd_dev, msg->parm.register_msg);
2240
    goto out;
2240
 goto out;
2241
    break;
2241
 break;
2242
  case FUSD_FOPS_REPLY:
2242
 case FUSD_FOPS_REPLY:
2243
    /* if reply is successful, DO NOT free the message */
2243
 /* if reply is successful, DO NOT free the message */
2244
    if ((retval = fusd_fops_reply(fusd_dev, msg)) == 0) {
2244
 if ((retval = fusd_fops_reply(fusd_dev, msg)) == 0) {
2245
      yield = 1;
2245
 yield = 1;
2246
      goto out_no_free;
2246
 goto out_no_free;
2247
    }
2247
 }
2248
    break;
2248
 break;
2249
  case FUSD_FOPS_NONBLOCK_REPLY:
2249
 case FUSD_FOPS_NONBLOCK_REPLY:
2250
    switch (msg->subcmd) {
2250
 switch (msg->subcmd) {
2251
    case FUSD_POLL_DIFF:
2251
 case FUSD_POLL_DIFF:
2252
      retval = fusd_polldiff_reply(fusd_dev, msg);
2252
 retval = fusd_polldiff_reply(fusd_dev, msg);
2253
      break;
2253
 break;
2254
    default:
2254
 default:
2255
      RDEBUG(2, "fusd_fops_nonblock got unknown subcmd %d", msg->subcmd);
2255
 RDEBUG(2, "fusd_fops_nonblock got unknown subcmd %d", msg->subcmd);
2256
      retval = -EINVAL;
2256
 retval = -EINVAL;
2257
    }
2257
 }
2258
    break;
2258
 break;
2259
  default:
2259
 default:
2260
    RDEBUG(2, "warning: unknown message type of %d received!", msg->cmd);
2260
 RDEBUG(2, "warning: unknown message type of %d received!", msg->cmd);
2261
    retval = -EINVAL;
2261
 retval = -EINVAL;
2262
    goto out;
2262
 goto out;
2263
    break;
2263
 break;
2264
  }
2264
 }
2265
2265
2266
2266
2267
 out:
2267
 out:
2268
  if (msg && msg->data) {
2268
 if (msg && msg->data) {
2269
    VFREE(msg->data);
2269
 VFREE(msg->data);
2270
    msg->data = NULL;
2270
 msg->data = NULL;
2271
  }
2271
 }
2272
  if (msg != NULL) {
2272
 if (msg != NULL) {
2273
    KFREE(msg);
2273
 KFREE(msg);
2274
    msg = NULL;
2274
 msg = NULL;
2275
  }
2275
 }
2276
2276
2277
 out_no_free:
2277
 out_no_free:
2278
2278
2279
  /* the functions we call indicate success by returning 0.  we
2279
 /* the functions we call indicate success by returning 0. we
2280
   * convert that into a success indication by changing the retval to
2280
 * convert that into a success indication by changing the retval to
2281
   * the length of the write. */
2281
 * the length of the write. */
2282
  if (retval == 0)
2282
 if (retval == 0)
2283
    retval = user_data_len + user_msg_len;
2283
 retval = user_data_len + user_msg_len;
2284
2284
2285
  UNLOCK_FUSD_DEV(fusd_dev);
2285
 UNLOCK_FUSD_DEV(fusd_dev);
2286
2286
2287
  /* if we successfully completed someone's syscall, yield the
2287
 /* if we successfully completed someone's syscall, yield the
2288
   * processor to them immediately as a throughput optimization.  we
2288
 * processor to them immediately as a throughput optimization. we
2289
   * also hope that in the case of bulk data transfer, their next
2289
 * also hope that in the case of bulk data transfer, their next
2290
   * syscall will come in before we are scheduled again. */
2290
 * syscall will come in before we are scheduled again. */
2291
  if (yield) {
2291
 if (yield) {
2292
#ifdef SCHED_YIELD
2292
#ifdef SCHED_YIELD
2293
    current->policy |= SCHED_YIELD;
2293
 current->policy |= SCHED_YIELD;
2294
#endif
2294
#endif
2295
    schedule();
2295
 schedule();
2296
  }
2296
 }
2297
2297
2298
  return retval;
2298
 return retval;
2299
2299
2300
 zombie_dev:
2300
 zombie_dev:
2301
 invalid_dev:
2301
 invalid_dev:
2302
  RDEBUG(1, "fusd_process_write: got invalid device!");
2302
 RDEBUG(1, "fusd_process_write: got invalid device!");
2303
  return -EPIPE;
2303
 return -EPIPE;
2304
}
2304
}
2305
2305
2306
2306
2307
STATIC ssize_t fusd_write(struct file *file,
2307
STATIC ssize_t fusd_write(struct file *file,
2308
    const char *buffer,
2308
 const char *buffer,
2309
    size_t length,
2309
 size_t length,
2310
    loff_t *offset)
2310
 loff_t *offset)
2311
{
2311
{
2312
  return fusd_process_write(file, buffer, length, NULL, 0);
2312
 return fusd_process_write(file, buffer, length, NULL, 0);
2313
}
2313
}
2314
2314
2315
2315
2316
#if 0
2316
STATIC ssize_t fusd_writev(struct file *file,
2317
STATIC ssize_t fusd_writev(struct file *file,
2317
			   const struct iovec *iov,
2318
 const struct iovec *iov,
2318
			   unsigned long count,
2319
 unsigned long count,
2319
			   loff_t *offset)
2320
 loff_t *offset)
2320
{
2321
#else
2321
  if (count != 2) {
2322
STATIC ssize_t fusd_aio_write(struct kiocb *iocb,
2322
    RDEBUG(2, "fusd_writev: got illegal iov count of %ld", count);
2323
 const struct iovec *iov,
2323
    return -EINVAL;
2324
 unsigned long count,
2324
  }
2325
 loff_t pos)
2325
2326
#endif
2326
  return fusd_process_write(file,
2327
{
2327
			    iov[0].iov_base, iov[0].iov_len,
2328
 if (count != 2) {
2328
			    iov[1].iov_base, iov[1].iov_len);
2329
 RDEBUG(2, "fusd_writev: got illegal iov count of %ld", count);
2330
 return -EINVAL;
2331
 }
2332
2333
 return fusd_process_write(iocb->ki_filp,
2334
 iov[0].iov_base, iov[0].iov_len,
2335
 iov[1].iov_base, iov[1].iov_len);
2329
}
2336
}
2330
2337
2331
2338
Lines 2333-2598 Link Here
2333
 * waiting to go from kernel to userspace.
2340
 * waiting to go from kernel to userspace.
2334
 *
2341
 *
2335
 * Important note: there are 2 possible read modes;
2342
 * Important note: there are 2 possible read modes;
2336
 *   1) header-read mode; just the fusd_msg structure is returned.
2343
 * 1) header-read mode; just the fusd_msg structure is returned.
2337
 *
2344
 *
2338
 *   2) data-read mode; the data portion of a call (NOT including the
2345
 * 2) data-read mode; the data portion of a call (NOT including the
2339
 *   fusd_msg structure) is returned.
2346
 * fusd_msg structure) is returned.
2340
 *
2347
 *
2341
 * The protocol this function expects the user-space library to follow
2348
 * The protocol this function expects the user-space library to follow
2342
 * is:
2349
 * is:
2343
 *   1) Userspace library reads header.
2350
 * 1) Userspace library reads header.
2344
 *   2) If fusd_msg->datalen == 0, goto step 4.
2351
 * 2) If fusd_msg->datalen == 0, goto step 4.
2345
 *   3) Userspace library reads data.
2352
 * 3) Userspace library reads data.
2346
 *   4) Message gets dequeued by the kernel.
2353
 * 4) Message gets dequeued by the kernel.
2347
 *
2354
 *
2348
 * In other words, userspace first reads the header.  Then, if and
2355
 * In other words, userspace first reads the header. Then, if and
2349
 * only if the header you read indicates that data follows, userspace
2356
 * only if the header you read indicates that data follows, userspace
2350
 * follows with a read for that data.
2357
 * follows with a read for that data.
2351
 *
2358
 *
2352
 * For the header read, the length requested MUST be the exact length
2359
 * For the header read, the length requested MUST be the exact length
2353
 * sizeof(fusd_msg_t).  The corresponding data read must request
2360
 * sizeof(fusd_msg_t). The corresponding data read must request
2354
 * exactly the number of bytes in the data portion of the message.  NO
2361
 * exactly the number of bytes in the data portion of the message. NO
2355
 * OTHER READ LENGTHS ARE ALLOWED - ALL OTHER READ LENGTHS WILL GET AN
2362
 * OTHER READ LENGTHS ARE ALLOWED - ALL OTHER READ LENGTHS WILL GET AN
2356
 * -EINVAL.  This is done as a basic safety measure to make sure we're
2363
 * -EINVAL. This is done as a basic safety measure to make sure we're
2357
 * talking to a userspace library that understands our protocol, and
2364
 * talking to a userspace library that understands our protocol, and
2358
 * to detect framing errors.
2365
 * to detect framing errors.
2359
 *
2366
 *
2360
 * (note: normally you'd have to worry about reentrancy in a function
2367
 * (note: normally you'd have to worry about reentrancy in a function
2361
 * like this because the process can block on the userspace access and
2368
 * like this because the process can block on the userspace access and
2362
 * another might try to read.  usually we would copy the message into
2369
 * another might try to read. usually we would copy the message into
2363
 * a temp location to make sure two processes don't get the same
2370
 * a temp location to make sure two processes don't get the same
2364
 * message.  however in this very specialized case, we're okay,
2371
 * message. however in this very specialized case, we're okay,
2365
 * because each instance of /dev/fusd has a completely independent
2372
 * because each instance of /dev/fusd has a completely independent
2366
 * message queue.)  */
2373
 * message queue.) */
2367
2374
2368
2375
2369
/* do a "header" read: used by fusd_read */
2376
/* do a "header" read: used by fusd_read */
2370
STATIC int fusd_read_header(char *user_buffer, size_t user_length, fusd_msg_t *msg)
2377
STATIC int fusd_read_header(char *user_buffer, size_t user_length, fusd_msg_t *msg)
2371
{
2378
{
2372
  int len = sizeof(fusd_msg_t);
2379
 int len = sizeof(fusd_msg_t);
2373
2380
2374
  if (user_length != len) {
2381
 if (user_length != len) {
2375
    RDEBUG(4, "bad length of %d sent to /dev/fusd for peek", (int) user_length);
2382
 RDEBUG(4, "bad length of %d sent to /dev/fusd for peek", (int) user_length);
2376
    return -EINVAL;
2383
 return -EINVAL;
2377
  }
2384
 }
2378
2385
2379
  if (copy_to_user(user_buffer, msg, len))
2386
 if (copy_to_user(user_buffer, msg, len))
2380
    return -EFAULT;
2387
 return -EFAULT;
2381
2388
2382
  return sizeof(fusd_msg_t);
2389
 return sizeof(fusd_msg_t);
2383
}
2390
}
2384
2391
2385
2392
2386
/* do a "data" read: used by fusd_read */
2393
/* do a "data" read: used by fusd_read */
2387
STATIC int fusd_read_data(char *user_buffer, size_t user_length, fusd_msg_t *msg)
2394
STATIC int fusd_read_data(char *user_buffer, size_t user_length, fusd_msg_t *msg)
2388
{
2395
{
2389
  int len = msg->datalen;
2396
 int len = msg->datalen;
2390
2397
2391
  if (len == 0 || msg->data == NULL) {
2398
 if (len == 0 || msg->data == NULL) {
2392
    RDEBUG(1, "fusd_read_data: no data to send!");
2399
 RDEBUG(1, "fusd_read_data: no data to send!");
2393
    return -EIO;
2400
 return -EIO;
2394
  }
2401
 }
2395
2402
2396
  /* make sure the user is requesting exactly the right amount (as a
2403
 /* make sure the user is requesting exactly the right amount (as a
2397
     sanity check) */
2404
 sanity check) */
2398
  if (user_length != len) {
2405
 if (user_length != len) {
2399
    RDEBUG(4, "bad read for %d bytes on /dev/fusd (need %d)", (int) user_length,len);
2406
 RDEBUG(4, "bad read for %d bytes on /dev/fusd (need %d)", (int) user_length,len);
2400
    return -EINVAL;
2407
 return -EINVAL;
2401
  }
2408
 }
2402
2409
2403
  /* now copy to userspace */
2410
 /* now copy to userspace */
2404
  if (copy_to_user(user_buffer, msg->data, len))
2411
 if (copy_to_user(user_buffer, msg->data, len))
2405
    return -EFAULT;
2412
 return -EFAULT;
2406
2413
2407
  /* done! */
2414
 /* done! */
2408
  return len;
2415
 return len;
2409
}
2416
}
2410
2417
2411
2418
2412
STATIC ssize_t fusd_read(struct file *file,
2419
STATIC ssize_t fusd_read(struct file *file,
2413
    char *user_buffer,    /* The buffer to fill with data */
2420
 char *user_buffer, /* The buffer to fill with data */
2414
    size_t user_length,   /* The length of the buffer */
2421
 size_t user_length, /* The length of the buffer */
2415
    loff_t *offset)  /* Our offset in the file */
2422
 loff_t *offset) /* Our offset in the file */
2416
{
2423
{
2417
  fusd_dev_t *fusd_dev;
2424
 fusd_dev_t *fusd_dev;
2418
  fusd_msgC_t *msg_out;
2425
 fusd_msgC_t *msg_out;
2419
  int retval, dequeue = 0;
2426
 int retval, dequeue = 0;
2420
2427
2421
  GET_FUSD_DEV(file->private_data, fusd_dev);
2428
 GET_FUSD_DEV(file->private_data, fusd_dev);
2422
  LOCK_FUSD_DEV(fusd_dev);
2429
 LOCK_FUSD_DEV(fusd_dev);
2423
2430
2424
  RDEBUG(15, "driver pid %d (/dev/%s) entering fusd_read", current->pid,
2431
 RDEBUG(15, "driver pid %d (/dev/%s) entering fusd_read", current->pid,
2425
	 NAME(fusd_dev));
2432
 NAME(fusd_dev));
2426
2433
2427
  /* if no messages are waiting, either block or return EAGAIN */
2434
 /* if no messages are waiting, either block or return EAGAIN */
2428
  while ((msg_out = fusd_dev->msg_head) == NULL) {
2435
 while ((msg_out = fusd_dev->msg_head) == NULL) {
2429
    DECLARE_WAITQUEUE(wait, current);
2436
 DECLARE_WAITQUEUE(wait, current);
2430
2437
2431
    if (file->f_flags & O_NONBLOCK) {
2438
 if (file->f_flags & O_NONBLOCK) {
2432
      retval = -EAGAIN;
2439
 retval = -EAGAIN;
2433
      goto out;
2440
 goto out;
2434
    }
2441
 }
2435
2442
2436
    /*
2443
 /*
2437
     * sleep, waiting for a message to arrive.  we are unrolling
2444
 * sleep, waiting for a message to arrive. we are unrolling
2438
     * interruptible_sleep_on to avoid a race between unlocking the
2445
 * interruptible_sleep_on to avoid a race between unlocking the
2439
     * device and sleeping (what if a message arrives in that
2446
 * device and sleeping (what if a message arrives in that
2440
     * interval?)
2447
 * interval?)
2441
     */
2448
 */
2442
    current->state = TASK_INTERRUPTIBLE;
2449
 current->state = TASK_INTERRUPTIBLE;
2443
    add_wait_queue(&fusd_dev->dev_wait, &wait);
2450
 add_wait_queue(&fusd_dev->dev_wait, &wait);
2444
    UNLOCK_FUSD_DEV(fusd_dev);
2451
 UNLOCK_FUSD_DEV(fusd_dev);
2445
    schedule();
2452
 schedule();
2446
    remove_wait_queue(&fusd_dev->dev_wait, &wait);
2453
 remove_wait_queue(&fusd_dev->dev_wait, &wait);
2447
    LOCK_FUSD_DEV(fusd_dev);
2454
 LOCK_FUSD_DEV(fusd_dev);
2448
2455
2449
    /* we're back awake!  --see if a signal woke us up */
2456
 /* we're back awake! --see if a signal woke us up */
2450
    if (signal_pending(current)) {
2457
 if (signal_pending(current)) {
2451
      retval = -ERESTARTSYS;
2458
 retval = -ERESTARTSYS;
2452
      goto out;
2459
 goto out;
2453
    }
2460
 }
2454
  }
2461
 }
2455
2462
2456
  /* is this a header read or data read? */
2463
 /* is this a header read or data read? */
2457
  if (!msg_out->peeked) {
2464
 if (!msg_out->peeked) {
2458
    /* this is a header read (first read) */
2465
 /* this is a header read (first read) */
2459
    retval = fusd_read_header(user_buffer, user_length, &msg_out->fusd_msg);
2466
 retval = fusd_read_header(user_buffer, user_length, &msg_out->fusd_msg);
2460
2467
2461
    /* is there data?  if so, make sure next read gets data.  if not,
2468
 /* is there data? if so, make sure next read gets data. if not,
2462
     * make sure message is dequeued now.*/
2469
 * make sure message is dequeued now.*/
2463
    if (msg_out->fusd_msg.datalen) {
2470
 if (msg_out->fusd_msg.datalen) {
2464
      msg_out->peeked = 1;
2471
 msg_out->peeked = 1;
2465
      dequeue = 0;
2472
 dequeue = 0;
2466
    } else {
2473
 } else {
2467
      dequeue = 1;
2474
 dequeue = 1;
2468
    }
2475
 }
2469
  } else {
2476
 } else {
2470
    /* this is a data read (second read) */
2477
 /* this is a data read (second read) */
2471
    retval = fusd_read_data(user_buffer, user_length, &msg_out->fusd_msg);
2478
 retval = fusd_read_data(user_buffer, user_length, &msg_out->fusd_msg);
2472
    dequeue = 1; /* message should be dequeued */
2479
 dequeue = 1; /* message should be dequeued */
2473
  }
2480
 }
2474
2481
2475
  /* if this message is done, take it out of the outgoing queue */
2482
 /* if this message is done, take it out of the outgoing queue */
2476
  if (dequeue) {
2483
 if (dequeue) {
2477
    if (fusd_dev->msg_tail == fusd_dev->msg_head)
2484
 if (fusd_dev->msg_tail == fusd_dev->msg_head)
2478
      fusd_dev->msg_tail = fusd_dev->msg_head = NULL;
2485
 fusd_dev->msg_tail = fusd_dev->msg_head = NULL;
2479
    else
2486
 else
2480
      fusd_dev->msg_head = msg_out->next;
2487
 fusd_dev->msg_head = msg_out->next;
2481
    FREE_FUSD_MSGC(msg_out);
2488
 FREE_FUSD_MSGC(msg_out);
2482
  }
2489
 }
2483
2490
2484
 out:
2491
 out:
2485
  UNLOCK_FUSD_DEV(fusd_dev);
2492
 UNLOCK_FUSD_DEV(fusd_dev);
2486
  return retval;
2493
 return retval;
2487
2494
2488
 zombie_dev:
2495
 zombie_dev:
2489
 invalid_dev:
2496
 invalid_dev:
2490
  RDEBUG(2, "got read on /dev/fusd for unknown device!");
2497
 RDEBUG(2, "got read on /dev/fusd for unknown device!");
2491
  return -EPIPE;
2498
 return -EPIPE;
2492
}
2499
}
2493
2500
2494
2501
2495
/* a poll on /dev/fusd itself (the control channel) */
2502
/* a poll on /dev/fusd itself (the control channel) */
2496
STATIC unsigned int fusd_poll(struct file *file, poll_table *wait)
2503
STATIC unsigned int fusd_poll(struct file *file, poll_table *wait)
2497
{
2504
{
2498
  fusd_dev_t *fusd_dev;
2505
 fusd_dev_t *fusd_dev;
2499
  GET_FUSD_DEV(file->private_data, fusd_dev);
2506
 GET_FUSD_DEV(file->private_data, fusd_dev);
2500
2507
2501
  poll_wait(file, &fusd_dev->dev_wait, wait);
2508
 poll_wait(file, &fusd_dev->dev_wait, wait);
2502
2509
2503
  if (fusd_dev->msg_head != NULL) {
2510
 if (fusd_dev->msg_head != NULL) {
2504
    return POLLIN | POLLRDNORM;
2511
 return POLLIN | POLLRDNORM;
2505
  }
2512
 }
2506
2513
2507
 invalid_dev:
2514
 invalid_dev:
2508
  return 0;
2515
 return 0;
2509
}
2516
}
2510
2517
2511
2518
2512
STATIC struct file_operations fusd_fops = {
2519
STATIC struct file_operations fusd_fops = {
2513
  owner:    THIS_MODULE,
2520
 owner: THIS_MODULE,
2514
  open:     fusd_open,
2521
 open: fusd_open,
2515
  read:     fusd_read,
2522
 read: fusd_read,
2516
  write:    fusd_write,
2523
 write: fusd_write,
2517
  writev:   fusd_writev,
2524
#if 0
2518
  release:  fusd_release,
2525
 writev: fusd_writev,
2519
  poll:     fusd_poll,
2526
#else
2527
 aio_write:fusd_aio_write,
2528
#endif
2529
 release: fusd_release,
2530
 poll: fusd_poll,
2520
};
2531
};
2521
  
2532
2522
2533
2523
2534
2524
/*************************************************************************/
2535
/*************************************************************************/
2525
2536
2526
typedef struct fusd_status_state {
2537
typedef struct fusd_status_state {
2527
  int binary_status;
2538
 int binary_status;
2528
  int need_new_status;
2539
 int need_new_status;
2529
  char *curr_status;
2540
 char *curr_status;
2530
  int curr_status_len;
2541
 int curr_status_len;
2531
  int last_version_seen;
2542
 int last_version_seen;
2532
} fusd_statcontext_t;
2543
} fusd_statcontext_t;
2533
2544
2534
/* open() called on /dev/fusd/status */
2545
/* open() called on /dev/fusd/status */
2535
STATIC int fusd_status_open(struct inode *inode, struct file *file)
2546
STATIC int fusd_status_open(struct inode *inode, struct file *file)
2536
{
2547
{
2537
  int error = 0;
2548
 int error = 0;
2538
  fusd_statcontext_t *fs;
2549
 fusd_statcontext_t *fs;
2539
2550
2540
  //MOD_INC_USE_COUNT;
2551
 //MOD_INC_USE_COUNT;
2541
2552
2542
  if ((fs = KMALLOC(sizeof(fusd_statcontext_t), GFP_KERNEL)) == NULL) {
2553
 if ((fs = KMALLOC(sizeof(fusd_statcontext_t), GFP_KERNEL)) == NULL) {
2543
    RDEBUG(1, "yikes!  kernel can't allocate memory");
2554
 RDEBUG(1, "yikes! kernel can't allocate memory");
2544
    error = -ENOMEM;
2555
 error = -ENOMEM;
2545
    goto out;
2556
 goto out;
2546
  }
2557
 }
2547
2558
2548
  memset(fs, 0, sizeof(fusd_statcontext_t));
2559
 memset(fs, 0, sizeof(fusd_statcontext_t));
2549
  fs->need_new_status = 1;
2560
 fs->need_new_status = 1;
2550
  file->private_data = (void *) fs;
2561
 file->private_data = (void *) fs;
2551
2562
2552
 out:
2563
 out:
2553
  //if (error)
2564
 //if (error)
2554
  //  MOD_DEC_USE_COUNT;
2565
 // MOD_DEC_USE_COUNT;
2555
  return error;
2566
 return error;
2556
}
2567
}
2557
2568
2558
/* close on /dev/fusd_status */
2569
/* close on /dev/fusd_status */
2559
STATIC int fusd_status_release(struct inode *inode, struct file *file)
2570
STATIC int fusd_status_release(struct inode *inode, struct file *file)
2560
{
2571
{
2561
  fusd_statcontext_t *fs = (fusd_statcontext_t *) file->private_data;
2572
 fusd_statcontext_t *fs = (fusd_statcontext_t *) file->private_data;
2562
2573
2563
  if (fs) {
2574
 if (fs) {
2564
    if (fs->curr_status)
2575
 if (fs->curr_status)
2565
      KFREE(fs->curr_status);
2576
 KFREE(fs->curr_status);
2566
    KFREE(fs);
2577
 KFREE(fs);
2567
  }
2578
 }
2568
2579
2569
  //MOD_DEC_USE_COUNT;
2580
 //MOD_DEC_USE_COUNT;
2570
  return 0;
2581
 return 0;
2571
}
2582
}
2572
2583
2573
2584
2574
/* ioctl() on /dev/fusd/status */
2585
/* ioctl() on /dev/fusd/status */
2575
STATIC int fusd_status_ioctl(struct inode *inode, struct file *file,
2586
STATIC int fusd_status_ioctl(struct inode *inode, struct file *file,
2576
				 unsigned int cmd, unsigned long arg)
2587
 unsigned int cmd, unsigned long arg)
2577
{
2588
{
2578
  fusd_statcontext_t *fs = (fusd_statcontext_t *) file->private_data;
2589
 fusd_statcontext_t *fs = (fusd_statcontext_t *) file->private_data;
2579
2590
2580
  if (!fs)
2591
 if (!fs)
2581
    return -EIO;
2592
 return -EIO;
2582
2593
2583
  switch (cmd) {
2594
 switch (cmd) {
2584
  case FUSD_STATUS_USE_BINARY:
2595
 case FUSD_STATUS_USE_BINARY:
2585
    fs->binary_status = 1;
2596
 fs->binary_status = 1;
2586
    return 0;
2597
 return 0;
2587
  default:
2598
 default:
2588
    return -EINVAL;
2599
 return -EINVAL;
2589
    break;
2600
 break;
2590
  }
2601
 }
2591
}
2602
}
2592
2603
2593
2604
2594
/*
2605
/*
2595
 * maybe_expand_buffer: expand a buffer exponentially as it fills.  We
2606
 * maybe_expand_buffer: expand a buffer exponentially as it fills. We
2596
 * are given:
2607
 * are given:
2597
 *
2608
 *
2598
 * - A reference to a pointer to a buffer (buf)
2609
 * - A reference to a pointer to a buffer (buf)
Lines 2601-2626 Link Here
2601
 * - The amount of space we want to ensure is free in the buffer (space_needed)
2612
 * - The amount of space we want to ensure is free in the buffer (space_needed)
2602
 *
2613
 *
2603
 * If there isn't at least space_needed difference between buf_size
2614
 * If there isn't at least space_needed difference between buf_size
2604
 * and len, the existing contents are moved into a larger buffer. 
2615
 * and len, the existing contents are moved into a larger buffer.
2605
 */
2616
 */
2606
STATIC int maybe_expand_buffer(char **buf, int *buf_size, int len,
2617
STATIC int maybe_expand_buffer(char **buf, int *buf_size, int len,
2607
			       int space_needed)
2618
 int space_needed)
2608
{
2619
{
2609
  if (*buf_size - len < space_needed) {
2620
 if (*buf_size - len < space_needed) {
2610
    char *old_buf = *buf;
2621
 char *old_buf = *buf;
2611
2622
2612
    *buf_size *= 2;
2623
 *buf_size *= 2;
2613
    *buf = KMALLOC(*buf_size, GFP_KERNEL);
2624
 *buf = KMALLOC(*buf_size, GFP_KERNEL);
2614
2625
2615
    if (*buf != NULL)
2626
 if (*buf != NULL)
2616
      memmove(*buf, old_buf, len);
2627
 memmove(*buf, old_buf, len);
2617
    KFREE(old_buf);
2628
 KFREE(old_buf);
2618
    if (*buf == NULL) {
2629
 if (*buf == NULL) {
2619
      RDEBUG(1, "out of memory!");
2630
 RDEBUG(1, "out of memory!");
2620
      return -1;
2631
 return -1;
2621
    }
2632
 }
2622
  }
2633
 }
2623
  return 0;
2634
 return 0;
2624
}
2635
}
2625
2636
2626
2637
Lines 2628-2972 Link Here
2628
/* Build a text buffer containing current fusd status. */
2639
/* Build a text buffer containing current fusd status. */
2629
STATIC void fusd_status_build_text(fusd_statcontext_t *fs)
2640
STATIC void fusd_status_build_text(fusd_statcontext_t *fs)
2630
{
2641
{
2631
  int buf_size = 512;
2642
 int buf_size = 512;
2632
  char *buf = KMALLOC(buf_size, GFP_KERNEL);
2643
 char *buf = KMALLOC(buf_size, GFP_KERNEL);
2633
  int len = 0, total_clients = 0, total_files = 0;
2644
 int len = 0, total_clients = 0, total_files = 0;
2634
  struct list_head *tmp;
2645
 struct list_head *tmp;
2635
2646
2636
  if (buf == NULL) {
2647
 if (buf == NULL) {
2637
    RDEBUG(1, "fusd_status_build: out of memory!");
2648
 RDEBUG(1, "fusd_status_build: out of memory!");
2638
    return;
2649
 return;
2639
  }
2650
 }
2640
2651
2641
  len += snprintf(buf + len, buf_size - len,
2652
 len += snprintf(buf + len, buf_size - len,
2642
		  "  PID  Open Name\n"
2653
 " PID Open Name\n"
2643
		  "------ ---- -----------------\n");
2654
 "------ ---- -----------------\n");
2644
2655
2645
  down(&fusd_devlist_sem);
2656
 down(&fusd_devlist_sem);
2646
  list_for_each(tmp, &fusd_devlist_head) {
2657
 list_for_each(tmp, &fusd_devlist_head) {
2647
    fusd_dev_t *d = list_entry(tmp, fusd_dev_t, devlist);
2658
 fusd_dev_t *d = list_entry(tmp, fusd_dev_t, devlist);
2648
2659
2649
    if (!d)
2660
 if (!d)
2650
      continue;
2661
 continue;
2651
2662
2652
    /* Possibly expand the buffer if we need more space */
2663
 /* Possibly expand the buffer if we need more space */
2653
    if (maybe_expand_buffer(&buf, &buf_size, len, FUSD_MAX_NAME_LENGTH+120) < 0)
2664
 if (maybe_expand_buffer(&buf, &buf_size, len, FUSD_MAX_NAME_LENGTH+120) < 0)
2654
      goto out;
2665
 goto out;
2655
2666
2656
    len += snprintf(buf + len, buf_size - len,
2667
 len += snprintf(buf + len, buf_size - len,
2657
		    "%6d %4d %s%s\n", d->pid, d->num_files,
2668
 "%6d %4d %s%s\n", d->pid, d->num_files,
2658
		    d->zombie ? "<zombie>" : "", NAME(d));
2669
 d->zombie ? "<zombie>" : "", NAME(d));
2659
2670
2660
    total_files++;
2671
 total_files++;
2661
    total_clients += d->num_files;
2672
 total_clients += d->num_files;
2662
  }
2673
 }
2663
2674
2664
  len += snprintf(buf + len, buf_size - len,
2675
 len += snprintf(buf + len, buf_size - len,
2665
		  "\nFUSD $Revision: 1.97-kor-hacked-11 $ - %d devices used by %d clients\n",
2676
 "\nFUSD $Revision: 1.97-kor-hacked-11 $ - %d devices used by %d clients\n",
2666
		  total_files, total_clients);
2677
 total_files, total_clients);
2667
2678
2668
 out:
2679
 out:
2669
  fs->last_version_seen = last_version;
2680
 fs->last_version_seen = last_version;
2670
  up(&fusd_devlist_sem);
2681
 up(&fusd_devlist_sem);
2671
2682
2672
  if (fs->curr_status)
2683
 if (fs->curr_status)
2673
    KFREE(fs->curr_status);
2684
 KFREE(fs->curr_status);
2674
2685
2675
  fs->curr_status = buf;
2686
 fs->curr_status = buf;
2676
  fs->curr_status_len = len;
2687
 fs->curr_status_len = len;
2677
  fs->need_new_status = 0;
2688
 fs->need_new_status = 0;
2678
}
2689
}
2679
2690
2680
2691
2681
/* Build the binary version of status */
2692
/* Build the binary version of status */
2682
STATIC void fusd_status_build_binary(fusd_statcontext_t *fs)
2693
STATIC void fusd_status_build_binary(fusd_statcontext_t *fs)
2683
{
2694
{
2684
  int buf_size = 512;
2695
 int buf_size = 512;
2685
  char *buf = KMALLOC(buf_size, GFP_KERNEL);
2696
 char *buf = KMALLOC(buf_size, GFP_KERNEL);
2686
  int len = 0, i = 0;
2697
 int len = 0, i = 0;
2687
  struct list_head *tmp;
2698
 struct list_head *tmp;
2688
  fusd_status_t *s;
2699
 fusd_status_t *s;
2689
2700
2690
  if (buf == NULL) {
2701
 if (buf == NULL) {
2691
    RDEBUG(1, "out of memory!");
2702
 RDEBUG(1, "out of memory!");
2692
    return;
2703
 return;
2693
  }
2704
 }
2694
2705
2695
  down(&fusd_devlist_sem);
2706
 down(&fusd_devlist_sem);
2696
  list_for_each(tmp, &fusd_devlist_head) {
2707
 list_for_each(tmp, &fusd_devlist_head) {
2697
    fusd_dev_t *d = list_entry(tmp, fusd_dev_t, devlist);
2708
 fusd_dev_t *d = list_entry(tmp, fusd_dev_t, devlist);
2698
2709
2699
    if (!d)
2710
 if (!d)
2700
      continue;
2711
 continue;
2701
2712
2702
    /* Possibly expand the buffer if we need more space */
2713
 /* Possibly expand the buffer if we need more space */
2703
    if (maybe_expand_buffer(&buf, &buf_size, len, sizeof(fusd_status_t)) < 0)
2714
 if (maybe_expand_buffer(&buf, &buf_size, len, sizeof(fusd_status_t)) < 0)
2704
      goto out;
2715
 goto out;
2705
2716
2706
    s = &((fusd_status_t *) buf)[i];
2717
 s = &((fusd_status_t *) buf)[i];
2707
2718
2708
    /* construct this status entry */
2719
 /* construct this status entry */
2709
    memset(s, 0, sizeof(fusd_status_t));
2720
 memset(s, 0, sizeof(fusd_status_t));
2710
    strncpy(s->name, NAME(d), FUSD_MAX_NAME_LENGTH);
2721
 strncpy(s->name, NAME(d), FUSD_MAX_NAME_LENGTH);
2711
    s->zombie   = d->zombie;
2722
 s->zombie = d->zombie;
2712
    s->pid      = d->pid;
2723
 s->pid = d->pid;
2713
    s->num_open = d->num_files;
2724
 s->num_open = d->num_files;
2714
2725
2715
    i++;
2726
 i++;
2716
    len += sizeof(fusd_status_t);
2727
 len += sizeof(fusd_status_t);
2717
  }
2728
 }
2718
  
2729
2719
 out:
2730
 out:
2720
  fs->last_version_seen = last_version;
2731
 fs->last_version_seen = last_version;
2721
  up(&fusd_devlist_sem);
2732
 up(&fusd_devlist_sem);
2722
2733
2723
  if (fs->curr_status)
2734
 if (fs->curr_status)
2724
    KFREE(fs->curr_status);
2735
 KFREE(fs->curr_status);
2725
2736
2726
  fs->curr_status = buf;
2737
 fs->curr_status = buf;
2727
  fs->curr_status_len = len;
2738
 fs->curr_status_len = len;
2728
  fs->need_new_status = 0;
2739
 fs->need_new_status = 0;
2729
}
2740
}
2730
2741
2731
2742
2732
2743
2733
STATIC ssize_t fusd_status_read(struct file *file,
2744
STATIC ssize_t fusd_status_read(struct file *file,
2734
    char *user_buffer,    /* The buffer to fill with data */
2745
 char *user_buffer, /* The buffer to fill with data */
2735
    size_t user_length,   /* The length of the buffer */
2746
 size_t user_length, /* The length of the buffer */
2736
    loff_t *offset)  /* Our offset in the file */
2747
 loff_t *offset) /* Our offset in the file */
2737
{
2748
{
2738
  fusd_statcontext_t *fs = (fusd_statcontext_t *) file->private_data;
2749
 fusd_statcontext_t *fs = (fusd_statcontext_t *) file->private_data;
2739
2750
2740
  if (!fs)
2751
 if (!fs)
2741
    return -EIO;
2752
 return -EIO;
2742
2753
2743
  /* create a new status page, if we aren't in the middle of one */
2754
 /* create a new status page, if we aren't in the middle of one */
2744
  if (fs->need_new_status) {
2755
 if (fs->need_new_status) {
2745
    if (fs->binary_status)
2756
 if (fs->binary_status)
2746
      fusd_status_build_binary(fs);
2757
 fusd_status_build_binary(fs);
2747
    else
2758
 else
2748
      fusd_status_build_text(fs);
2759
 fusd_status_build_text(fs);
2749
  }
2760
 }
2750
2761
2751
  /* return EOF if we're at the end */
2762
 /* return EOF if we're at the end */
2752
  if (fs->curr_status == NULL || fs->curr_status_len == 0) {
2763
 if (fs->curr_status == NULL || fs->curr_status_len == 0) {
2753
    fs->need_new_status = 1;
2764
 fs->need_new_status = 1;
2754
    return 0;
2765
 return 0;
2755
  }
2766
 }
2756
2767
2757
  /* return only as much data as we have */
2768
 /* return only as much data as we have */
2758
  if (fs->curr_status_len < user_length)
2769
 if (fs->curr_status_len < user_length)
2759
    user_length = fs->curr_status_len;
2770
 user_length = fs->curr_status_len;
2760
  if (copy_to_user(user_buffer, fs->curr_status, user_length))
2771
 if (copy_to_user(user_buffer, fs->curr_status, user_length))
2761
    return -EFAULT;
2772
 return -EFAULT;
2762
2773
2763
  /* update fs, so we don't return the same data next time */
2774
 /* update fs, so we don't return the same data next time */
2764
  fs->curr_status_len -= user_length;
2775
 fs->curr_status_len -= user_length;
2765
  if (fs->curr_status_len)
2776
 if (fs->curr_status_len)
2766
    memmove(fs->curr_status, fs->curr_status + user_length, fs->curr_status_len);
2777
 memmove(fs->curr_status, fs->curr_status + user_length, fs->curr_status_len);
2767
  else {
2778
 else {
2768
    KFREE(fs->curr_status);
2779
 KFREE(fs->curr_status);
2769
    fs->curr_status = NULL;
2780
 fs->curr_status = NULL;
2770
  }
2781
 }
2771
2782
2772
  return user_length;
2783
 return user_length;
2773
}
2784
}
2774
2785
2775
2786
2776
/* a poll on /dev/fusd itself (the control channel) */
2787
/* a poll on /dev/fusd itself (the control channel) */
2777
STATIC unsigned int fusd_status_poll(struct file *file, poll_table *wait)
2788
STATIC unsigned int fusd_status_poll(struct file *file, poll_table *wait)
2778
{
2789
{
2779
  fusd_statcontext_t *fs = (fusd_statcontext_t *) file->private_data;
2790
 fusd_statcontext_t *fs = (fusd_statcontext_t *) file->private_data;
2780
2791
2781
  poll_wait(file, &new_device_wait, wait);
2792
 poll_wait(file, &new_device_wait, wait);
2782
2793
2783
  if (fs->last_version_seen < last_version)
2794
 if (fs->last_version_seen < last_version)
2784
    return POLLIN | POLLRDNORM;
2795
 return POLLIN | POLLRDNORM;
2785
  else
2796
 else
2786
    return 0;
2797
 return 0;
2787
}
2798
}
2788
2799
2789
2800
2790
STATIC struct file_operations fusd_status_fops = {
2801
STATIC struct file_operations fusd_status_fops = {
2791
  owner:    THIS_MODULE,
2802
 owner: THIS_MODULE,
2792
  open:     fusd_status_open,
2803
 open: fusd_status_open,
2793
  ioctl:    fusd_status_ioctl,
2804
 ioctl: fusd_status_ioctl,
2794
  read:     fusd_status_read,
2805
 read: fusd_status_read,
2795
  release:  fusd_status_release,
2806
 release: fusd_status_release,
2796
  poll:     fusd_status_poll,
2807
 poll: fusd_status_poll,
2797
};
2808
};
2798
  
2809
2799
2810
2800
/*************************************************************************/
2811
/*************************************************************************/
2801
2812
2802
2813
2803
STATIC int init_fusd(void)
2814
STATIC int init_fusd(void)
2804
{
2815
{
2805
	int retval;
2816
 int retval;
2806
2817
2807
#ifdef CONFIG_FUSD_MEMDEBUG
2818
#ifdef CONFIG_FUSD_MEMDEBUG
2808
  if ((retval = fusd_mem_init()) < 0)
2819
 if ((retval = fusd_mem_init()) < 0)
2809
    return retval;
2820
 return retval;
2810
#endif
2821
#endif
2811
2822
2812
2823
2813
  printk(KERN_INFO
2824
 printk(KERN_INFO
2814
	 "fusd: starting, $Revision: 1.97-kor-hacked-11 $, $Date: 2003/07/11 22:29:39 $");
2825
 "fusd: starting, $Revision: 1.97-kor-hacked-11 $, $Date: 2003/07/11 22:29:39 $");
2815
#ifdef CVSTAG
2826
#ifdef CVSTAG
2816
  printk(", release %s", CVSTAG);
2827
 printk(", release %s", CVSTAG);
2817
#endif
2828
#endif
2818
#ifdef CONFIG_FUSD_DEBUG
2829
#ifdef CONFIG_FUSD_DEBUG
2819
  printk(", debuglevel=%d\n", fusd_debug_level);
2830
 printk(", debuglevel=%d\n", fusd_debug_level);
2820
#else
2831
#else
2821
  printk(", debugging messages disabled\n");
2832
 printk(", debugging messages disabled\n");
2822
#endif
2833
#endif
2823
2834
2824
	fusd_control_device = NULL;
2835
 fusd_control_device = NULL;
2825
	fusd_status_device = NULL;
2836
 fusd_status_device = NULL;
2826
	
2837
2827
	fusd_class = class_create(THIS_MODULE, "fusd");
2838
 fusd_class = class_create(THIS_MODULE, "fusd");
2828
	if(IS_ERR(fusd_class))
2839
 if(IS_ERR(fusd_class))
2829
	{
2840
 {
2830
		retval = PTR_ERR(fusd_class);
2841
 retval = PTR_ERR(fusd_class);
2831
		printk("class_create failed status: %d\n", retval);
2842
 printk("class_create failed status: %d\n", retval);
2832
		goto fail0;
2843
 goto fail0;
2833
	}
2844
 }
2834
	
2845
2835
	control_id = 0;
2846
 control_id = 0;
2836
2847
2837
	if((retval = alloc_chrdev_region(&control_id, 0, 1, FUSD_CONTROL_FILENAME)) < 0)
2848
 if((retval = alloc_chrdev_region(&control_id, 0, 1, FUSD_CONTROL_FILENAME)) < 0)
2838
	{
2849
 {
2839
		printk("alloc_chrdev_region failed status: %d\n", retval);
2850
 printk("alloc_chrdev_region failed status: %d\n", retval);
2840
		goto fail1;
2851
 goto fail1;
2841
	}
2852
 }
2842
#ifdef CONFIG_DEVFS_FS
2853
#ifdef CONFIG_DEVFS_FS
2843
	if((retval = devfs_mk_cdev(control_id, S_IFCHR | 0666, FUSD_CONTROL_FILENAME)) < 0)
2854
 if((retval = devfs_mk_cdev(control_id, S_IFCHR | 0666, FUSD_CONTROL_FILENAME)) < 0)
2844
	{
2855
 {
2845
		printk("devfs_mk_cdev failed status: %d\n", retval);
2856
 printk("devfs_mk_cdev failed status: %d\n", retval);
2846
		goto fail2;
2857
 goto fail2;
2847
	}
2858
 }
2848
#endif
2859
#endif
2849
2860
2850
	fusd_control_device = cdev_alloc();
2861
 fusd_control_device = cdev_alloc();
2851
	if(fusd_control_device == NULL)
2862
 if(fusd_control_device == NULL)
2852
	{
2863
 {
2853
		retval = -ENOMEM;
2864
 retval = -ENOMEM;
2854
		goto fail3;
2865
 goto fail3;
2855
	}
2866
 }
2856
2867
2857
	fusd_control_device->owner = THIS_MODULE;
2868
 fusd_control_device->owner = THIS_MODULE;
2858
	fusd_control_device->ops = &fusd_fops;
2869
 fusd_control_device->ops = &fusd_fops;
2859
	kobject_set_name(&fusd_control_device->kobj, FUSD_CONTROL_FILENAME);
2870
 kobject_set_name(&fusd_control_device->kobj, FUSD_CONTROL_FILENAME);
2860
2871
2861
	printk("cdev control id: %d\n", control_id);
2872
 printk("cdev control id: %d\n", control_id);
2862
	if((retval = cdev_add(fusd_control_device, control_id, 1)) < 0)
2873
 if((retval = cdev_add(fusd_control_device, control_id, 1)) < 0)
2863
	{
2874
 {
2864
		printk("cdev_add failed status: %d\n", retval);
2875
 printk("cdev_add failed status: %d\n", retval);
2865
		kobject_put(&fusd_control_device->kobj);
2876
 kobject_put(&fusd_control_device->kobj);
2866
		goto fail4;
2877
 goto fail4;
2867
	}
2878
 }
2868
	
2879
2869
	fusd_control_class_device = CLASS_DEVICE_CREATE(fusd_class, NULL, control_id, NULL, "control");
2880
 fusd_control_class_device = CLASS_DEVICE_CREATE(fusd_class, NULL, control_id, NULL, "control");
2870
	if(fusd_control_class_device == NULL)
2881
 if(fusd_control_class_device == NULL)
2871
	{
2882
 {
2872
		retval = PTR_ERR(fusd_control_class_device);
2883
 retval = PTR_ERR(fusd_control_class_device);
2873
		printk("class_device_create failed status: %d\n", retval);
2884
 printk("class_device_create failed status: %d\n", retval);
2874
		goto fail5;
2885
 goto fail5;
2875
	}
2886
 }
2876
2887
2877
	status_id = 0;
2888
 status_id = 0;
2878
2889
2879
	if((retval = alloc_chrdev_region(&status_id, 0, 1, FUSD_STATUS_FILENAME)) < 0)
2890
 if((retval = alloc_chrdev_region(&status_id, 0, 1, FUSD_STATUS_FILENAME)) < 0)
2880
	{
2891
 {
2881
		printk("alloc_chrdev_region failed status: %d\n", retval);
2892
 printk("alloc_chrdev_region failed status: %d\n", retval);
2882
		goto fail6;
2893
 goto fail6;
2883
	}
2894
 }
2884
#ifdef CONFIG_DEVFS_FS
2895
#ifdef CONFIG_DEVFS_FS
2885
	if((retval = devfs_mk_cdev(status_id, S_IFCHR | 0666, FUSD_STATUS_FILENAME)) < 0)
2896
 if((retval = devfs_mk_cdev(status_id, S_IFCHR | 0666, FUSD_STATUS_FILENAME)) < 0)
2886
	{
2897
 {
2887
		printk("devfs_mk_cdev failed status: %d\n", retval);
2898
 printk("devfs_mk_cdev failed status: %d\n", retval);
2888
		goto fail7;
2899
 goto fail7;
2889
	}
2900
 }
2890
#endif
2901
#endif
2891
2902
2892
	fusd_status_device = cdev_alloc();
2903
 fusd_status_device = cdev_alloc();
2893
	if(fusd_status_device == NULL)
2904
 if(fusd_status_device == NULL)
2894
	{
2905
 {
2895
		retval = -ENOMEM;
2906
 retval = -ENOMEM;
2896
		goto fail8;
2907
 goto fail8;
2897
	}
2908
 }
2898
2909
2899
	fusd_status_device->owner = THIS_MODULE;
2910
 fusd_status_device->owner = THIS_MODULE;
2900
	fusd_status_device->ops = &fusd_status_fops;
2911
 fusd_status_device->ops = &fusd_status_fops;
2901
	kobject_set_name(&fusd_status_device->kobj, FUSD_STATUS_FILENAME);
2912
 kobject_set_name(&fusd_status_device->kobj, FUSD_STATUS_FILENAME);
2902
2913
2903
	if((retval = cdev_add(fusd_status_device, status_id, 1)) < 0)
2914
 if((retval = cdev_add(fusd_status_device, status_id, 1)) < 0)
2904
	{
2915
 {
2905
		printk("cdev_add failed status: %d\n", retval);
2916
 printk("cdev_add failed status: %d\n", retval);
2906
		kobject_put(&fusd_status_device->kobj);
2917
 kobject_put(&fusd_status_device->kobj);
2907
		goto fail9;
2918
 goto fail9;
2908
	}
2919
 }
2909
	
2920
2910
	fusd_status_class_device = CLASS_DEVICE_CREATE(fusd_class, NULL, status_id, NULL, "status");
2921
 fusd_status_class_device = CLASS_DEVICE_CREATE(fusd_class, NULL, status_id, NULL, "status");
2911
	if(fusd_status_class_device == NULL)
2922
 if(fusd_status_class_device == NULL)
2912
	{
2923
 {
2913
		printk("class_device_create failed status: %d\n", retval);
2924
 printk("class_device_create failed status: %d\n", retval);
2914
		retval = PTR_ERR(fusd_status_class_device);
2925
 retval = PTR_ERR(fusd_status_class_device);
2915
		goto fail10;
2926
 goto fail10;
2916
	}
2927
 }
2917
	
2928
2918
  RDEBUG(1, "registration successful");
2929
 RDEBUG(1, "registration successful");
2919
  return 0;
2930
 return 0;
2920
2931
2921
fail10:
2932
fail10:
2922
	cdev_del(fusd_status_device);
2933
 cdev_del(fusd_status_device);
2923
fail9:
2934
fail9:
2924
	kfree(fusd_status_device);
2935
 kfree(fusd_status_device);
2925
fail8:
2936
fail8:
2926
#ifdef CONFIG_DEVFS_FS
2937
#ifdef CONFIG_DEVFS_FS
2927
	devfs_remove(FUSD_STATUS_FILENAME);
2938
 devfs_remove(FUSD_STATUS_FILENAME);
2928
#endif
2939
#endif
2929
fail7:
2940
/*fail7:*/
2930
	unregister_chrdev_region(status_id, 1);
2941
 unregister_chrdev_region(status_id, 1);
2931
fail6:
2942
fail6:
2932
	class_device_destroy(fusd_class, control_id);
2943
 class_device_destroy(fusd_class, control_id);
2933
fail5:
2944
fail5:
2934
	cdev_del(fusd_control_device);
2945
 cdev_del(fusd_control_device);
2935
fail4:
2946
fail4:
2936
	kfree(fusd_control_device);
2947
 kfree(fusd_control_device);
2937
fail3:
2948
fail3:
2938
#ifdef CONFIG_DEVFS_FS
2949
#ifdef CONFIG_DEVFS_FS
2939
	devfs_remove(FUSD_CONTROL_FILENAME);
2950
 devfs_remove(FUSD_CONTROL_FILENAME);
2940
#endif
2951
#endif
2941
fail2:
2952
/*fail2:*/
2942
	unregister_chrdev_region(control_id, 1);
2953
 unregister_chrdev_region(control_id, 1);
2943
2954
2944
fail1:
2955
fail1:
2945
	class_destroy(fusd_class);
2956
 class_destroy(fusd_class);
2946
fail0:
2957
fail0:
2947
	return retval;
2958
 return retval;
2948
}
2959
}
2949
2960
2950
STATIC void cleanup_fusd(void)
2961
STATIC void cleanup_fusd(void)
2951
{
2962
{
2952
  RDEBUG(1, "cleaning up");
2963
 RDEBUG(1, "cleaning up");
2953
2964
2954
	class_device_destroy(fusd_class, status_id);
2965
 class_device_destroy(fusd_class, status_id);
2955
	class_device_destroy(fusd_class, control_id);
2966
 class_device_destroy(fusd_class, control_id);
2956
	
2957
	cdev_del(fusd_control_device);
2958
	cdev_del(fusd_status_device);
2959
2967
2960
  devfs_remove(FUSD_CONTROL_FILENAME);
2968
 cdev_del(fusd_control_device);
2961
  devfs_remove(FUSD_STATUS_FILENAME);
2969
 cdev_del(fusd_status_device);
2962
2970
2971
#ifdef CONFIG_DEVFS_FS
2972
 devfs_remove(FUSD_CONTROL_FILENAME);
2973
 devfs_remove(FUSD_STATUS_FILENAME);
2974
#endif
2975
2976
 class_destroy(fusd_class);
2963
2977
2964
	class_destroy(fusd_class);
2965
	
2966
#ifdef CONFIG_FUSD_MEMDEBUG
2978
#ifdef CONFIG_FUSD_MEMDEBUG
2967
  fusd_mem_cleanup();
2979
 fusd_mem_cleanup();
2968
#endif
2980
#endif
2969
}
2981
}
2970
2982
2971
module_init(init_fusd);
2983
module_init(init_fusd);
2972
module_exit(cleanup_fusd);
2984
module_exit(cleanup_fusd);
2985

Return to bug 96449