From: Andy P. <at...@us...> - 2002-04-09 14:08:19
|
Update of /cvsroot/linux-vax/kernel-2.4/fs/devfs In directory usw-pr-cvs1:/tmp/cvs-serv27691/devfs Modified Files: base.c util.c Log Message: sync 2.4.15 commit 11 Index: base.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/devfs/base.c,v retrieving revision 1.1.1.2 retrieving revision 1.2 diff -u -r1.1.1.2 -r1.2 --- base.c 25 Feb 2001 23:14:48 -0000 1.1.1.2 +++ base.c 9 Apr 2002 13:11:17 -0000 1.2 @@ -1,6 +1,6 @@ /* devfs (Device FileSystem) driver. - Copyright (C) 1998-2000 Richard Gooch + Copyright (C) 1998-2001 Richard Gooch This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -388,7 +388,7 @@ Work sponsored by SGI. v0.83 19991107 Richard Gooch <rg...@at...> [...1783 lines suppressed...] } /* End Function devfsd_close */ -int __init init_devfs_fs (void) +static int __init init_devfs_fs (void) { int err; @@ -3364,8 +3333,10 @@ { int err; - if ( (boot_options & OPTION_NOMOUNT) ) return; + if ( !(boot_options & OPTION_MOUNT) ) return; err = do_mount ("none", "/dev", "devfs", 0, ""); if (err == 0) printk ("Mounted devfs on /dev\n"); else printk ("Warning: unable to mount devfs, err: %d\n", err); } /* End Function mount_devfs_fs */ + +module_init(init_devfs_fs) Index: util.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/devfs/util.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- util.c 14 Jan 2001 16:40:09 -0000 1.1.1.1 +++ util.c 9 Apr 2002 13:11:17 -0000 1.2 @@ -1,6 +1,6 @@ /* devfs (Device FileSystem) utilities. - Copyright (C) 1999-2000 Richard Gooch + Copyright (C) 1999-2001 Richard Gooch This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -33,12 +33,29 @@ 20000622 Richard Gooch <rg...@at...> Took account of interface change to <devfs_mk_symlink>. Took account of interface change to <devfs_mk_dir>. + 20010519 Richard Gooch <rg...@at...> + Documentation cleanup. + 20010709 Richard Gooch <rg...@at...> + Created <devfs_*alloc_major> and <devfs_*alloc_devnum>. + 20010710 Richard Gooch <rg...@at...> + Created <devfs_*alloc_unique_number>. + 20010730 Richard Gooch <rg...@at...> + Documentation typo fix. + 20010806 Richard Gooch <rg...@at...> + Made <block_semaphore> and <char_semaphore> private. + 20010813 Richard Gooch <rg...@at...> + Fixed bug in <devfs_alloc_unique_number>: limited to 128 numbers + 20010818 Richard Gooch <rg...@at...> + Updated major masks up to Linus' "no new majors" proclamation. + Block: were 126 now 122 free, char: were 26 now 19 free. */ #include <linux/module.h> #include <linux/init.h> -#include <linux/locks.h> -#include <linux/kdev_t.h> #include <linux/devfs_fs_kernel.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> + +#include <asm/bitops.h> /* Private functions follow */ @@ -132,9 +149,10 @@ /** * devfs_register_series - Register a sequence of device entries. - * @dir: The handle to the parent devfs directory entry. If this is %NULL the - * new names are relative to the root of the devfs. + * @dir: The handle to the parent devfs directory entry. If this is %NULL + * the new names are relative to the root of the devfs. * @format: The printf-style format string. A single "\%u" is allowed. + * @num_entries: The number of entries to register. * @flags: A set of bitwise-ORed flags (DEVFS_FL_*). * @major: The major number. Not needed for regular files. * @minor_start: The starting minor number. Not needed for regular files. @@ -142,9 +160,9 @@ * @ops: The &file_operations or &block_device_operations structure. * This must not be externally deallocated. * @info: An arbitrary pointer which will be written to the private_data - * field of the &file structure passed to the device driver. You can set - * this to whatever you like, and change it once the file is opened (the next - * file opened will not see this change). + * field of the &file structure passed to the device driver. You + * can set this to whatever you like, and change it once the file + * is opened (the next file opened will not see this change). */ void devfs_register_series (devfs_handle_t dir, const char *format, @@ -163,3 +181,299 @@ } } /* End Function devfs_register_series */ EXPORT_SYMBOL(devfs_register_series); + + +struct major_list +{ + spinlock_t lock; + __u32 bits[8]; +}; + +/* Block majors already assigned: + 0-3, 7-9, 11-63, 65-99, 101-113, 120-127, 199, 201, 240-255 + Total free: 122 +*/ +static struct major_list block_major_list = +{SPIN_LOCK_UNLOCKED, + {0xfffffb8f, /* Majors 0 to 31 */ + 0xffffffff, /* Majors 32 to 63 */ + 0xfffffffe, /* Majors 64 to 95 */ + 0xff03ffef, /* Majors 96 to 127 */ + 0x00000000, /* Majors 128 to 159 */ + 0x00000000, /* Majors 160 to 191 */ + 0x00000280, /* Majors 192 to 223 */ + 0xffff0000} /* Majors 224 to 255 */ +}; + +/* Char majors already assigned: + 0-7, 9-151, 154-158, 160-211, 216-221, 224-230, 240-255 + Total free: 19 +*/ +static struct major_list char_major_list = +{SPIN_LOCK_UNLOCKED, + {0xfffffeff, /* Majors 0 to 31 */ + 0xffffffff, /* Majors 32 to 63 */ + 0xffffffff, /* Majors 64 to 95 */ + 0xffffffff, /* Majors 96 to 127 */ + 0x7cffffff, /* Majors 128 to 159 */ + 0xffffffff, /* Majors 160 to 191 */ + 0x3f0fffff, /* Majors 192 to 223 */ + 0xffff007f} /* Majors 224 to 255 */ +}; + + +/** + * devfs_alloc_major - Allocate a major number. + * @type: The type of the major (DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLK) + + * Returns the allocated major, else -1 if none are available. + * This routine is thread safe and does not block. + */ + +int devfs_alloc_major (char type) +{ + int major; + struct major_list *list; + + list = (type == DEVFS_SPECIAL_CHR) ? &char_major_list : &block_major_list; + spin_lock (&list->lock); + major = find_first_zero_bit (list->bits, 256); + if (major < 256) __set_bit (major, list->bits); + else major = -1; + spin_unlock (&list->lock); + return major; +} /* End Function devfs_alloc_major */ +EXPORT_SYMBOL(devfs_alloc_major); + + +/** + * devfs_dealloc_major - Deallocate a major number. + * @type: The type of the major (DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLK) + * @major: The major number. + * This routine is thread safe and does not block. + */ + +void devfs_dealloc_major (char type, int major) +{ + int was_set; + struct major_list *list; + + if (major < 0) return; + list = (type == DEVFS_SPECIAL_CHR) ? &char_major_list : &block_major_list; + spin_lock (&list->lock); + was_set = __test_and_clear_bit (major, list->bits); + spin_unlock (&list->lock); + if (!was_set) + printk (KERN_ERR __FUNCTION__ "(): major %d was already free\n", + major); +} /* End Function devfs_dealloc_major */ +EXPORT_SYMBOL(devfs_dealloc_major); + + +struct minor_list +{ + int major; + __u32 bits[8]; + struct minor_list *next; +}; + +struct device_list +{ + struct minor_list *first, *last; + int none_free; +}; + +static DECLARE_MUTEX (block_semaphore); +static struct device_list block_list; + +static DECLARE_MUTEX (char_semaphore); +static struct device_list char_list; + + +/** + * devfs_alloc_devnum - Allocate a device number. + * @type: The type (DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLK). + * + * Returns the allocated device number, else NODEV if none are available. + * This routine is thread safe and may block. + */ + +kdev_t devfs_alloc_devnum (char type) +{ + int minor; + struct semaphore *semaphore; + struct device_list *list; + struct minor_list *entry; + + if (type == DEVFS_SPECIAL_CHR) + { + semaphore = &char_semaphore; + list = &char_list; + } + else + { + semaphore = &block_semaphore; + list = &block_list; + } + if (list->none_free) return NODEV; /* Fast test */ + down (semaphore); + if (list->none_free) + { + up (semaphore); + return NODEV; + } + for (entry = list->first; entry != NULL; entry = entry->next) + { + minor = find_first_zero_bit (entry->bits, 256); + if (minor >= 256) continue; + __set_bit (minor, entry->bits); + up (semaphore); + return MKDEV (entry->major, minor); + } + /* Need to allocate a new major */ + if ( ( entry = kmalloc (sizeof *entry, GFP_KERNEL) ) == NULL ) + { + list->none_free = 1; + up (semaphore); + return NODEV; + } + memset (entry, 0, sizeof *entry); + if ( ( entry->major = devfs_alloc_major (type) ) < 0 ) + { + list->none_free = 1; + up (semaphore); + kfree (entry); + return NODEV; + } + __set_bit (0, entry->bits); + if (list->first == NULL) list->first = entry; + else list->last->next = entry; + list->last = entry; + up (semaphore); + return MKDEV (entry->major, 0); +} /* End Function devfs_alloc_devnum */ +EXPORT_SYMBOL(devfs_alloc_devnum); + + +/** + * devfs_dealloc_devnum - Dellocate a device number. + * @type: The type (DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLK). + * @devnum: The device number. + * + * This routine is thread safe and does not block. + */ + +void devfs_dealloc_devnum (char type, kdev_t devnum) +{ + int major, minor; + struct semaphore *semaphore; + struct device_list *list; + struct minor_list *entry; + + if (devnum == NODEV) return; + if (type == DEVFS_SPECIAL_CHR) + { + semaphore = &char_semaphore; + list = &char_list; + } + else + { + semaphore = &block_semaphore; + list = &block_list; + } + major = MAJOR (devnum); + minor = MINOR (devnum); + down (semaphore); + for (entry = list->first; entry != NULL; entry = entry->next) + { + int was_set; + + if (entry->major != major) continue; + was_set = __test_and_clear_bit (minor, entry->bits); + if (was_set) list->none_free = 0; + up (semaphore); + if (!was_set) + printk ( KERN_ERR __FUNCTION__ "(): device %s was already free\n", + kdevname (devnum) ); + return; + } + up (semaphore); + printk ( KERN_ERR __FUNCTION__ "(): major for %s not previously allocated\n", + kdevname (devnum) ); +} /* End Function devfs_dealloc_devnum */ +EXPORT_SYMBOL(devfs_dealloc_devnum); + + +/** + * devfs_alloc_unique_number - Allocate a unique (positive) number. + * @space: The number space to allocate from. + * + * Returns the allocated unique number, else a negative error code. + * This routine is thread safe and may block. + */ + +int devfs_alloc_unique_number (struct unique_numspace *space) +{ + int number; + unsigned int length; + __u32 *bits; + + /* Get around stupid lack of semaphore initialiser */ + spin_lock (&space->init_lock); + if (!space->sem_initialised) + { + sema_init (&space->semaphore, 1); + space->sem_initialised = 1; + } + spin_unlock (&space->init_lock); + down (&space->semaphore); + if (space->num_free < 1) + { + if (space->length < 16) length = 16; + else length = space->length << 1; + if ( ( bits = vmalloc (length) ) == NULL ) + { + up (&space->semaphore); + return -ENOMEM; + } + if (space->bits != NULL) + { + memcpy (bits, space->bits, space->length); + vfree (space->bits); + } + space->num_free = (length - space->length) << 3; + space->bits = bits; + memset (bits + space->length, 0, length - space->length); + space->length = length; + } + number = find_first_zero_bit (space->bits, space->length << 3); + --space->num_free; + __set_bit (number, space->bits); + up (&space->semaphore); + return number; +} /* End Function devfs_alloc_unique_number */ +EXPORT_SYMBOL(devfs_alloc_unique_number); + + +/** + * devfs_dealloc_unique_number - Deallocate a unique (positive) number. + * @space: The number space to deallocate from. + * @number: The number to deallocate. + * + * This routine is thread safe and may block. + */ + +void devfs_dealloc_unique_number (struct unique_numspace *space, int number) +{ + int was_set; + + if (number < 0) return; + down (&space->semaphore); + was_set = __test_and_clear_bit (number, space->bits); + if (was_set) ++space->num_free; + up (&space->semaphore); + if (!was_set) + printk (KERN_ERR __FUNCTION__ "(): number %d was already free\n", + number); +} /* End Function devfs_dealloc_unique_number */ +EXPORT_SYMBOL(devfs_dealloc_unique_number); |