util.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:13k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*  devfs (Device FileSystem) utilities.
  2.     Copyright (C) 1999-2002  Richard Gooch
  3.     This library is free software; you can redistribute it and/or
  4.     modify it under the terms of the GNU Library General Public
  5.     License as published by the Free Software Foundation; either
  6.     version 2 of the License, or (at your option) any later version.
  7.     This library is distributed in the hope that it will be useful,
  8.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  9.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  10.     Library General Public License for more details.
  11.     You should have received a copy of the GNU Library General Public
  12.     License along with this library; if not, write to the Free
  13.     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14.     Richard Gooch may be reached by email at  rgooch@atnf.csiro.au
  15.     The postal address is:
  16.       Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
  17.     ChangeLog
  18.     19991031   Richard Gooch <rgooch@atnf.csiro.au>
  19.                Created.
  20.     19991103   Richard Gooch <rgooch@atnf.csiro.au>
  21.                Created <_devfs_convert_name> and supported SCSI and IDE CD-ROMs
  22.     20000203   Richard Gooch <rgooch@atnf.csiro.au>
  23.                Changed operations pointer type to void *.
  24.     20000621   Richard Gooch <rgooch@atnf.csiro.au>
  25.                Changed interface to <devfs_register_series>.
  26.     20000622   Richard Gooch <rgooch@atnf.csiro.au>
  27.                Took account of interface change to <devfs_mk_symlink>.
  28.                Took account of interface change to <devfs_mk_dir>.
  29.     20010519   Richard Gooch <rgooch@atnf.csiro.au>
  30.                Documentation cleanup.
  31.     20010709   Richard Gooch <rgooch@atnf.csiro.au>
  32.                Created <devfs_*alloc_major> and <devfs_*alloc_devnum>.
  33.     20010710   Richard Gooch <rgooch@atnf.csiro.au>
  34.                Created <devfs_*alloc_unique_number>.
  35.     20010730   Richard Gooch <rgooch@atnf.csiro.au>
  36.                Documentation typo fix.
  37.     20010806   Richard Gooch <rgooch@atnf.csiro.au>
  38.                Made <block_semaphore> and <char_semaphore> private.
  39.     20010813   Richard Gooch <rgooch@atnf.csiro.au>
  40.                Fixed bug in <devfs_alloc_unique_number>: limited to 128 numbers
  41.     20010818   Richard Gooch <rgooch@atnf.csiro.au>
  42.                Updated major masks up to Linus' "no new majors" proclamation.
  43.        Block: were 126 now 122 free, char: were 26 now 19 free.
  44.     20020324   Richard Gooch <rgooch@atnf.csiro.au>
  45.                Fixed bug in <devfs_alloc_unique_number>: was clearing beyond
  46.        bitfield.
  47.     20020326   Richard Gooch <rgooch@atnf.csiro.au>
  48.                Fixed bitfield data type for <devfs_*alloc_devnum>.
  49.                Made major bitfield type and initialiser 64 bit safe.
  50.     20020413   Richard Gooch <rgooch@atnf.csiro.au>
  51.                Fixed shift warning on 64 bit machines.
  52.     20020428   Richard Gooch <rgooch@atnf.csiro.au>
  53.                Copied and used macro for error messages from fs/devfs/base.c 
  54. */
  55. #include <linux/module.h>
  56. #include <linux/init.h>
  57. #include <linux/devfs_fs_kernel.h>
  58. #include <linux/slab.h>
  59. #include <linux/vmalloc.h>
  60. #include <asm/bitops.h>
  61. #define PRINTK(format, args...) 
  62.    {printk (KERN_ERR "%s" format, __FUNCTION__ , ## args);}
  63. /*  Private functions follow  */
  64. /**
  65.  * devfs_register_tape - Register a tape device in the "/dev/tapes" hierarchy.
  66.  * @de: Any tape device entry in the device directory.
  67.  */
  68. void devfs_register_tape (devfs_handle_t de)
  69. {
  70.     int pos;
  71.     devfs_handle_t parent, slave;
  72.     char name[16], dest[64];
  73.     static unsigned int tape_counter;
  74.     static devfs_handle_t tape_dir;
  75.     if (tape_dir == NULL) tape_dir = devfs_mk_dir (NULL, "tapes", NULL);
  76.     parent = devfs_get_parent (de);
  77.     pos = devfs_generate_path (parent, dest + 3, sizeof dest - 3);
  78.     if (pos < 0) return;
  79.     strncpy (dest + pos, "../", 3);
  80.     sprintf (name, "tape%u", tape_counter++);
  81.     devfs_mk_symlink (tape_dir, name, DEVFS_FL_DEFAULT, dest + pos,
  82.       &slave, NULL);
  83.     devfs_auto_unregister (de, slave);
  84. }   /*  End Function devfs_register_tape  */
  85. EXPORT_SYMBOL(devfs_register_tape);
  86. /**
  87.  * devfs_register_series - Register a sequence of device entries.
  88.  * @dir: The handle to the parent devfs directory entry. If this is %NULL
  89.  * the new names are relative to the root of the devfs.
  90.  * @format: The printf-style format string. A single "%u" is allowed.
  91.  * @num_entries: The number of entries to register.
  92.  * @flags: A set of bitwise-ORed flags (DEVFS_FL_*).
  93.  * @major: The major number. Not needed for regular files.
  94.  * @minor_start: The starting minor number. Not needed for regular files.
  95.  * @mode: The default file mode.
  96.  * @ops: The &file_operations or &block_device_operations structure.
  97.  * This must not be externally deallocated.
  98.  * @info: An arbitrary pointer which will be written to the private_data
  99.  * field of the &file structure passed to the device driver. You
  100.  * can set this to whatever you like, and change it once the file
  101.  * is opened (the next file opened will not see this change).
  102.  */
  103. void devfs_register_series (devfs_handle_t dir, const char *format,
  104.     unsigned int num_entries, unsigned int flags,
  105.     unsigned int major, unsigned int minor_start,
  106.     umode_t mode, void *ops, void *info)
  107. {
  108.     unsigned int count;
  109.     char devname[128];
  110.     for (count = 0; count < num_entries; ++count)
  111.     {
  112. sprintf (devname, format, count);
  113. devfs_register (dir, devname, flags, major, minor_start + count,
  114. mode, ops, info);
  115.     }
  116. }   /*  End Function devfs_register_series  */
  117. EXPORT_SYMBOL(devfs_register_series);
  118. struct major_list
  119. {
  120.     spinlock_t lock;
  121.     unsigned long bits[256 / BITS_PER_LONG];
  122. };
  123. #if BITS_PER_LONG == 32
  124. #  define INITIALISER64(low,high) (low), (high)
  125. #else
  126. #  define INITIALISER64(low,high) ( (unsigned long) (high) << 32 | (low) )
  127. #endif
  128. /*  Block majors already assigned:
  129.     0-3, 7-9, 11-63, 65-99, 101-113, 120-127, 199, 201, 240-255
  130.     Total free: 122
  131. */
  132. static struct major_list block_major_list =
  133. {SPIN_LOCK_UNLOCKED,
  134.     {INITIALISER64 (0xfffffb8f, 0xffffffff),  /*  Majors 0-31,    32-63    */
  135.      INITIALISER64 (0xfffffffe, 0xff03ffef),  /*  Majors 64-95,   96-127   */
  136.      INITIALISER64 (0x00000000, 0x00000000),  /*  Majors 128-159, 160-191  */
  137.      INITIALISER64 (0x00000280, 0xffff0000),  /*  Majors 192-223, 224-255  */
  138.     }
  139. };
  140. /*  Char majors already assigned:
  141.     0-7, 9-151, 154-158, 160-211, 216-221, 224-230, 240-255
  142.     Total free: 19
  143. */
  144. static struct major_list char_major_list =
  145. {SPIN_LOCK_UNLOCKED,
  146.     {INITIALISER64 (0xfffffeff, 0xffffffff),  /*  Majors 0-31,    32-63    */
  147.      INITIALISER64 (0xffffffff, 0xffffffff),  /*  Majors 64-95,   96-127   */
  148.      INITIALISER64 (0x7cffffff, 0xffffffff),  /*  Majors 128-159, 160-191  */
  149.      INITIALISER64 (0x3f0fffff, 0xffff007f),  /*  Majors 192-223, 224-255  */
  150.     }
  151. };
  152. /**
  153.  * devfs_alloc_major - Allocate a major number.
  154.  * @type: The type of the major (DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLK)
  155.  * Returns the allocated major, else -1 if none are available.
  156.  * This routine is thread safe and does not block.
  157.  */
  158. int devfs_alloc_major (char type)
  159. {
  160.     int major;
  161.     struct major_list *list;
  162.     list = (type == DEVFS_SPECIAL_CHR) ? &char_major_list : &block_major_list;
  163.     spin_lock (&list->lock);
  164.     major = find_first_zero_bit (list->bits, 256);
  165.     if (major < 256) __set_bit (major, list->bits);
  166.     else major = -1;
  167.     spin_unlock (&list->lock);
  168.     return major;
  169. }   /*  End Function devfs_alloc_major  */
  170. EXPORT_SYMBOL(devfs_alloc_major);
  171. /**
  172.  * devfs_dealloc_major - Deallocate a major number.
  173.  * @type: The type of the major (DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLK)
  174.  * @major: The major number.
  175.  * This routine is thread safe and does not block.
  176.  */
  177. void devfs_dealloc_major (char type, int major)
  178. {
  179.     int was_set;
  180.     struct major_list *list;
  181.     if (major < 0) return;
  182.     list = (type == DEVFS_SPECIAL_CHR) ? &char_major_list : &block_major_list;
  183.     spin_lock (&list->lock);
  184.     was_set = __test_and_clear_bit (major, list->bits);
  185.     spin_unlock (&list->lock);
  186.     if (!was_set) PRINTK ("(): major %d was already freen", major);
  187. }   /*  End Function devfs_dealloc_major  */
  188. EXPORT_SYMBOL(devfs_dealloc_major);
  189. struct minor_list
  190. {
  191.     int major;
  192.     unsigned long bits[256 / BITS_PER_LONG];
  193.     struct minor_list *next;
  194. };
  195. struct device_list
  196. {
  197.     struct minor_list *first, *last;
  198.     int none_free;
  199. };
  200. static DECLARE_MUTEX (block_semaphore);
  201. static struct device_list block_list;
  202. static DECLARE_MUTEX (char_semaphore);
  203. static struct device_list char_list;
  204. /**
  205.  * devfs_alloc_devnum - Allocate a device number.
  206.  * @type: The type (DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLK).
  207.  *
  208.  * Returns the allocated device number, else NODEV if none are available.
  209.  * This routine is thread safe and may block.
  210.  */
  211. kdev_t devfs_alloc_devnum (char type)
  212. {
  213.     int minor;
  214.     struct semaphore *semaphore;
  215.     struct device_list *list;
  216.     struct minor_list *entry;
  217.     if (type == DEVFS_SPECIAL_CHR)
  218.     {
  219. semaphore = &char_semaphore;
  220. list = &char_list;
  221.     }
  222.     else
  223.     {
  224. semaphore = &block_semaphore;
  225. list = &block_list;
  226.     }
  227.     if (list->none_free) return NODEV;  /*  Fast test  */
  228.     down (semaphore);
  229.     if (list->none_free)
  230.     {
  231. up (semaphore);
  232. return NODEV;
  233.     }
  234.     for (entry = list->first; entry != NULL; entry = entry->next)
  235.     {
  236. minor = find_first_zero_bit (entry->bits, 256);
  237. if (minor >= 256) continue;
  238. __set_bit (minor, entry->bits);
  239. up (semaphore);
  240. return mk_kdev (entry->major, minor);
  241.     }
  242.     /*  Need to allocate a new major  */
  243.     if ( ( entry = kmalloc (sizeof *entry, GFP_KERNEL) ) == NULL )
  244.     {
  245. list->none_free = 1;
  246. up (semaphore);
  247. return NODEV;
  248.     }
  249.     memset (entry, 0, sizeof *entry);
  250.     if ( ( entry->major = devfs_alloc_major (type) ) < 0 )
  251.     {
  252. list->none_free = 1;
  253. up (semaphore);
  254. kfree (entry);
  255. return NODEV;
  256.     }
  257.     __set_bit (0, entry->bits);
  258.     if (list->first == NULL) list->first = entry;
  259.     else list->last->next = entry;
  260.     list->last = entry;
  261.     up (semaphore);
  262.     return mk_kdev (entry->major, 0);
  263. }   /*  End Function devfs_alloc_devnum  */
  264. EXPORT_SYMBOL(devfs_alloc_devnum);
  265. /**
  266.  * devfs_dealloc_devnum - Dellocate a device number.
  267.  * @type: The type (DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLK).
  268.  * @devnum: The device number.
  269.  *
  270.  * This routine is thread safe and does not block.
  271.  */
  272. void devfs_dealloc_devnum (char type, kdev_t devnum)
  273. {
  274.     int major, minor;
  275.     struct semaphore *semaphore;
  276.     struct device_list *list;
  277.     struct minor_list *entry;
  278.     if ( kdev_none (devnum) ) return;
  279.     if (type == DEVFS_SPECIAL_CHR)
  280.     {
  281. semaphore = &char_semaphore;
  282. list = &char_list;
  283.     }
  284.     else
  285.     {
  286. semaphore = &block_semaphore;
  287. list = &block_list;
  288.     }
  289.     major = major (devnum);
  290.     minor = minor (devnum);
  291.     down (semaphore);
  292.     for (entry = list->first; entry != NULL; entry = entry->next)
  293.     {
  294. int was_set;
  295. if (entry->major != major) continue;
  296. was_set = __test_and_clear_bit (minor, entry->bits);
  297. if (was_set) list->none_free = 0;
  298. up (semaphore);
  299. if (!was_set)
  300.     PRINTK ( "(): device %s was already freen", kdevname (devnum) );
  301. return;
  302.     }
  303.     up (semaphore);
  304.     PRINTK ( "(): major for %s not previously allocatedn",
  305.      kdevname (devnum) );
  306. }   /*  End Function devfs_dealloc_devnum  */
  307. EXPORT_SYMBOL(devfs_dealloc_devnum);
  308. /**
  309.  * devfs_alloc_unique_number - Allocate a unique (positive) number.
  310.  * @space: The number space to allocate from.
  311.  *
  312.  * Returns the allocated unique number, else a negative error code.
  313.  * This routine is thread safe and may block.
  314.  */
  315. int devfs_alloc_unique_number (struct unique_numspace *space)
  316. {
  317.     int number;
  318.     unsigned int length;
  319.     /*  Get around stupid lack of semaphore initialiser  */
  320.     spin_lock (&space->init_lock);
  321.     if (!space->sem_initialised)
  322.     {
  323. sema_init (&space->semaphore, 1);
  324. space->sem_initialised = 1;
  325.     }
  326.     spin_unlock (&space->init_lock);
  327.     down (&space->semaphore);
  328.     if (space->num_free < 1)
  329.     {
  330. void *bits;
  331. if (space->length < 16) length = 16;
  332. else length = space->length << 1;
  333. if ( ( bits = vmalloc (length) ) == NULL )
  334. {
  335.     up (&space->semaphore);
  336.     return -ENOMEM;
  337. }
  338. if (space->bits != NULL)
  339. {
  340.     memcpy (bits, space->bits, space->length);
  341.     vfree (space->bits);
  342. }
  343. space->num_free = (length - space->length) << 3;
  344. space->bits = bits;
  345. memset (bits + space->length, 0, length - space->length);
  346. space->length = length;
  347.     }
  348.     number = find_first_zero_bit (space->bits, space->length << 3);
  349.     --space->num_free;
  350.     __set_bit (number, space->bits);
  351.     up (&space->semaphore);
  352.     return number;
  353. }   /*  End Function devfs_alloc_unique_number  */
  354. EXPORT_SYMBOL(devfs_alloc_unique_number);
  355. /**
  356.  * devfs_dealloc_unique_number - Deallocate a unique (positive) number.
  357.  * @space: The number space to deallocate from.
  358.  * @number: The number to deallocate.
  359.  *
  360.  * This routine is thread safe and may block.
  361.  */
  362. void devfs_dealloc_unique_number (struct unique_numspace *space, int number)
  363. {
  364.     int was_set;
  365.     if (number < 0) return;
  366.     down (&space->semaphore);
  367.     was_set = __test_and_clear_bit (number, space->bits);
  368.     if (was_set) ++space->num_free;
  369.     up (&space->semaphore);
  370.     if (!was_set) PRINTK ("(): number %d was already freen", number);
  371. }   /*  End Function devfs_dealloc_unique_number  */
  372. EXPORT_SYMBOL(devfs_dealloc_unique_number);