lkml.org 
[lkml]   [2003]   [Jan]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectRe: RFC/Patch - Implode devfs
	I have made a new version of my mini-devfs (attached below).
I have also made a first version of my devfs_helper program to handle
the functionality of devfsd on systems that use my mini-devfs.
devfs_helper is avaiable from the following location:

ftp://ftp.yggdrasil.com/pub/dist/device_control/devfs_helper/devfs_helper-0.1.tar.gz

This version of devfs_helper only supports "EXECUTE" and
"MODLOAD" actions, which may be the only events that are really
necessary. In the future, I envision eliminating the "MODLOAD"
action, since it is equivalent to
"EXECUTE modprobe -C /etc/modprobe.devfs $devname".

devfs_helper is currently 211 lines of C code. In comparison,
devfsd-1.3.25/*.[ch] is 3143 lines.

Also, here is version 2 of my mini-devfs. I am embarassed
to say that I omitted Richard Gooch's copyright notice on his code that
I copoied into mini-devfs/numspace.c. This patch corrects that and
fixes a variety of other little problems. It also changes the directory
of this facility to fs/mini-devfs/. One change that is necessary for
operation with devfs_helper is that the event names are now in all
capitals ("REGISTER" and "LOOKUP") to match the format of /etc/devfsd.conf.

mini-devfs has grown by 21 lines, mostly due to my restoring
Richard's copyright notice. Here is an updated size comparison in case
anyone is interested:

devfs 3614 lines 25,863 bytes
mini-devfs 650 lines 5,562 bytes
Reduction 5.6x 4.6x

--
Adam J. Richter __ ______________ 575 Oroville Road
adam@yggdrasil.com \ / Milpitas, California 95035
+1 408 309-6081 | g g d r a s i l United States of America
"Free Software For The Rest Of Us."
--- linux-2.5.53/include/linux/devfs_fs_kernel.h 2002-12-23 21:21:01.000000000 -0800
+++ linux/include/linux/devfs_fs_kernel.h 2002-12-31 18:45:59.000000000 -0800
@@ -24,7 +24,11 @@
#define DEVFS_SPECIAL_CHR 0
#define DEVFS_SPECIAL_BLK 1

+#ifdef CONFIG_DEVFS_SMALL
+typedef struct dentry * devfs_handle_t;
+#else
typedef struct devfs_entry * devfs_handle_t;
+#endif

#ifdef CONFIG_DEVFS_FS

--- linux-2.5.53/fs/namei.c 2002-12-23 21:19:59.000000000 -0800
+++ linux/fs/namei.c 2002-12-31 19:07:06.000000000 -0800
@@ -1377,9 +1377,9 @@
}

/* SMP-safe */
-static struct dentry *lookup_create(struct nameidata *nd, int is_dir)
+struct dentry *lookup_create(struct nameidata *nd, int is_dir)
{
struct dentry *dentry;

--- linux-2.5.53/fs/Kconfig 2002-12-23 21:20:32.000000000 -0800
+++ linux/fs/Kconfig 2002-12-31 18:45:59.000000000 -0800
@@ -847,7 +847,21 @@

If unsure, say N.

+config DEVFS_SMALL
+ bool "Smaller /dev file system (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && DEVFS_FS
+ ---help---
+ New smaller devfs without automatic partition rereading
+ (which impeded user level partition handling) and currently
+ without some features used by arch/ia64/sn.
+
+ If unsure, say N.
+
+config DEVFS_BIG
+ bool
+ depends on DEVFS_FS && !DEVFS_SMALL
+
config DEVFS_MOUNT
bool "Automatically mount at boot"
depends on DEVFS_FS
--- linux-2.5.53/fs/Makefile 2002-12-23 21:20:32.000000000 -0800
+++ linux/fs/Makefile 2002-12-31 18:45:59.000000000 -0800
@@ -65,7 +65,8 @@
obj-$(CONFIG_VFAT_FS) += vfat/
obj-$(CONFIG_BFS_FS) += bfs/
obj-$(CONFIG_ISO9660_FS) += isofs/
-obj-$(CONFIG_DEVFS_FS) += devfs/
+obj-$(CONFIG_DEVFS_BIG) += devfs/
+obj-$(CONFIG_DEVFS_SMALL) += mini-devfs/
obj-$(CONFIG_HFS_FS) += hfs/
obj-$(CONFIG_VXFS_FS) += freevxfs/
obj-$(CONFIG_NFS_FS) += nfs/
--- linux-2.5.53/fs/mini-devfs/Makefile 1969-12-31 16:00:00.000000000 -0800
+++ linux/fs/mini-devfs/Makefile 2002-12-31 18:45:59.000000000 -0800
@@ -0,0 +1,9 @@
+#
+# Makefile for the linux ramfs routines.
+#
+
+export-objs := inode.o numspace.o
+
+obj-$(CONFIG_RAMFS) += ramfs.o
+
+ramfs-objs := inode.o numspace.o
--- linux-2.5.53/fs/mini-devfs/inode.c 1969-12-31 16:00:00.000000000 -0800
+++ linux/fs/mini-devfs/inode.c 2002-12-31 22:28:02.000000000 -0800
@@ -0,0 +1,550 @@
+/*
+ * Stripped down Device File System (devfs2)
+ * Adapted from ramfs by Adam J. Richter. Ramfs was written by
+ * Linus Torvalds.
+ *
+ * Copyright (C) 2000 Linus Torvalds.
+ * 2000 Transmeta Corp.
+ * 2002 Yggdrasil Computing, Inc.
+ *
+ * Usage limits added to ramfs by David Gibson, Linuxcare Australia.
+ * This file is released under the GPL.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include <linux/highmem.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/smp_lock.h>
+#include <linux/backing-dev.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/namei.h>
+#include <linux/mount.h>
+
+#include <asm/uaccess.h>
+#include <asm/string.h>
+
+/* For now, must be the same as devfs magic to appease glibc. See
+ __posix_openpt in glibc-2.3/sysdeps/unix/sysv/linux/getpt.c
+ TODO(?): Adopt a new magic number and adjust glibc? */
+#define DEVFS2_MAGIC DEVFS_SUPER_MAGIC
+
+
+/* TODO: Move this to some .h file or, more likely, use a slightly
+ different interface from lookup_create. */
+extern struct dentry *lookup_create(struct nameidata *nd, int is_dir);
+
+static struct super_operations devfs2_ops;
+static struct address_space_operations devfs2_aops;
+static struct file_operations devfs2_file_operations;
+static struct inode_operations devfs2_dir_inode_operations;
+struct vfsmount *devfs2_vfsmount;
+
+static char devfs_helper[150] = "/sbin/devfs_helper";
+module_param_string(devfs_helper, devfs_helper, sizeof(devfs_helper), 0644);
+
+static struct backing_dev_info devfs2_backing_dev_info = {
+ .ra_pages = 0, /* No readahead */
+ .memory_backed = 1, /* Does not contribute to dirty memory */
+};
+
+static void devfs_event(const char *event, struct dentry *dentry)
+{
+ char path[64];
+
+ if (devfs_generate_path(dentry, path, sizeof(path)) == 0) {
+ const char *argv[] = { devfs_helper, event, path, NULL };
+ static char *envp[] = {"PATH=/bin:/sbin:/usr/bin:/usr/sbin",
+ "HOME=/", NULL };
+
+ /* FIXME: Change the call_usermodehelper prototype so
+ that argv and envp are type const so we won't have
+ to cast the type of argv. */
+ call_usermodehelper(devfs_helper, (char**) argv, envp);
+ } else
+ BUG();
+}
+
+static struct inode *devfs2_get_inode(struct super_block *sb, int mode, dev_t dev)
+{
+ struct inode * inode = new_inode(sb);
+
+ if (!inode)
+ return NULL;
+
+ inode->i_mode = mode;
+ inode->i_uid = current->fsuid;
+ inode->i_gid = current->fsgid;
+ inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_rdev = NODEV;
+ inode->i_mapping->a_ops = &devfs2_aops;
+ inode->i_mapping->backing_dev_info = &devfs2_backing_dev_info;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+
+ switch (mode & S_IFMT) {
+ default:
+ init_special_inode(inode, mode, dev);
+ break;
+ case S_IFREG:
+ inode->i_fop = &devfs2_file_operations;
+ break;
+ case S_IFDIR:
+ inode->i_op = &devfs2_dir_inode_operations;
+ inode->i_fop = &simple_dir_operations;
+
+ /* directory inodes start off with i_nlink == 2 (for "." entry) */
+ inode->i_nlink++;
+ break;
+ case S_IFLNK:
+ inode->i_op = &page_symlink_inode_operations;
+ break;
+ }
+
+ return inode;
+}
+
+static struct dentry * devfs2_lookup(struct inode *inode, struct dentry *dentry)
+{
+ // AJR commented out temporarily to address bug. -- try not AJR
+ devfs_event("LOOKUP", dentry);
+ return simple_lookup(inode, dentry);
+}
+
+
+/*
+ * File creation. Allocate an inode, and we're done..
+ */
+/* SMP-safe */
+static int
+devfs2_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
+{
+ struct inode * inode = devfs2_get_inode(dir->i_sb, mode, dev);
+ int error = -ENOSPC;
+
+ if (inode) {
+ d_instantiate(dentry, inode);
+ dget(dentry); /* Extra count - pin the dentry in core */
+ error = 0;
+ devfs_event("REGISTER", dentry);
+ }
+
+ return error;
+}
+
+static int devfs2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
+{
+ int retval = devfs2_mknod(dir, dentry, mode | S_IFDIR, 0);
+ if (!retval)
+ dir->i_nlink++;
+ return retval;
+}
+
+static int devfs2_create(struct inode *dir, struct dentry *dentry, int mode)
+{
+ return devfs2_mknod(dir, dentry, mode | S_IFREG, 0);
+}
+
+
+static int devfs2_symlink(struct inode * dir, struct dentry *dentry, const char * symname)
+{
+ struct inode *inode;
+ int error = -ENOSPC;
+
+ inode = devfs2_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0);
+ if (inode) {
+ int l = strlen(symname)+1;
+ error = page_symlink(inode, symname, l);
+ if (!error) {
+ d_instantiate(dentry, inode);
+ dget(dentry);
+ } else
+ iput(inode);
+ }
+ return error;
+}
+
+static struct address_space_operations devfs2_aops = {
+ .readpage = simple_readpage,
+ .prepare_write = simple_prepare_write,
+ .commit_write = simple_commit_write
+};
+
+static struct file_operations devfs2_file_operations = {
+ .read = generic_file_read,
+ .write = generic_file_write,
+ .mmap = generic_file_mmap,
+ .fsync = simple_sync_file,
+ .sendfile = generic_file_sendfile,
+};
+
+static struct inode_operations devfs2_dir_inode_operations = {
+ .create = devfs2_create,
+ .lookup = devfs2_lookup,
+ .link = simple_link,
+ .unlink = simple_unlink,
+ .symlink = devfs2_symlink,
+ .mkdir = devfs2_mkdir,
+ .rmdir = simple_rmdir,
+ .mknod = devfs2_mknod,
+ .rename = simple_rename,
+};
+
+static struct super_operations devfs2_ops = {
+ .statfs = simple_statfs,
+ .drop_inode = generic_delete_inode,
+};
+
+static int devfs2_fill_super(struct super_block * sb, void * data, int silent)
+{
+ struct inode *inode;
+ struct dentry *root;
+
+ sb->s_blocksize = PAGE_CACHE_SIZE;
+ sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+ sb->s_magic = DEVFS2_MAGIC;
+ sb->s_op = &devfs2_ops;
+ inode = devfs2_get_inode(sb, S_IFDIR | 0755, 0);
+ if (!inode)
+ return -ENOMEM;
+
+ root = d_alloc_root(inode);
+ if (!root) {
+ iput(inode);
+ return -ENOMEM;
+ }
+ sb->s_root = root;
+ return 0;
+}
+
+static struct super_block *devfs2_get_sb(struct file_system_type *fs_type,
+ int flags, char *dev_name, void *data)
+{
+ return get_sb_single(fs_type, flags, data, devfs2_fill_super);
+}
+
+static struct file_system_type devfs2_fs_type = {
+ .name = "devfs",
+ .get_sb = devfs2_get_sb,
+ .kill_sb = kill_litter_super,
+};
+
+static int __init init_devfs2_fs(void)
+{
+ int err;
+
+ if (devfs2_vfsmount != NULL)
+ return 0;
+
+ err = register_filesystem(&devfs2_fs_type);
+ if (err)
+ return err;
+
+ devfs2_vfsmount = kern_mount(&devfs2_fs_type);
+
+ if (IS_ERR(devfs2_vfsmount)) {
+ unregister_filesystem(&devfs2_fs_type);
+ return PTR_ERR(devfs2_vfsmount);
+ }
+ else
+ return 0;
+}
+
+static void __exit exit_devfs2_fs(void)
+{
+ unregister_filesystem(&devfs2_fs_type);
+}
+
+module_init(init_devfs2_fs)
+module_exit(exit_devfs2_fs)
+
+MODULE_LICENSE("GPL");
+
+/* Called and returns with dcache_lock held. */
+static int walk_parents_mkdir(const char **path, struct nameidata *nd,
+ int is_dir)
+{
+ char *slash;
+ char buf[strlen(*path)+1];
+ int err;
+
+ while ((slash = strchr(*path, '/')) != NULL) {
+ int len = slash - *path;
+ memcpy(buf, *path, len);
+ buf[len] = '\0';
+
+ spin_lock(&dcache_lock);
+ err = link_path_walk(buf, nd); /* releases dcache_lock */
+
+ BUG_ON(err); /* AJR */
+ if (err)
+ return err;
+
+ nd->dentry = lookup_create(nd, is_dir);
+
+ if (IS_ERR(nd->dentry)) {
+ BUG();
+ return PTR_ERR(nd->dentry);
+ }
+
+ if (!nd->dentry->d_inode)
+ err = vfs_mkdir(nd->dentry->d_parent->d_inode,
+ nd->dentry, 0644);
+
+ up(&nd->dentry->d_parent->d_inode->i_sem);
+
+ if (err) {
+ BUG_ON(err); /* AJR */
+ if (err)
+ return err;
+ }
+
+ *path += len + 1;
+ }
+ return 0;
+}
+
+/* On success, returns with (*parent_inode)->i_sem taken. */
+static int devfs_decode(devfs_handle_t dir, const char *name, int is_dir,
+ struct inode **parent_inode, struct dentry **dentry)
+{
+ struct nameidata nd;
+ int err;
+
+ if (dir == NULL) {
+ if (devfs2_vfsmount == NULL && init_devfs2_fs() != 0)
+ BUG();
+
+ dir = devfs2_vfsmount->mnt_sb->s_root;
+ }
+
+ memset(&nd, 0, sizeof(nd));
+ nd.flags = LOOKUP_PARENT;
+ /* nd.mnt = current->fs->rootmnt; FIXME? */
+ nd.mnt = devfs2_vfsmount;
+ nd.dentry = dir;
+
+ err = walk_parents_mkdir(&name, &nd, is_dir);
+ if (err)
+ return err;
+
+ spin_lock(&dcache_lock);
+ err = link_path_walk(name, &nd);
+ if (err) {
+ printk ("AJR devfs_decode: link_path_walk(name %s, &nd) got error %d.\n", name, err);
+ BUG();
+ return err;
+ }
+
+ *dentry = lookup_create(&nd, is_dir);
+
+ BUG_ON(IS_ERR(*dentry)); /* AJR */
+ if (IS_ERR(*dentry))
+ return PTR_ERR(*dentry);
+ else {
+ *parent_inode = (*dentry)->d_parent->d_inode;
+ return 0;
+ }
+}
+
+
+devfs_handle_t devfs_register (devfs_handle_t dir,
+ const char *name,
+ unsigned int flags,
+ unsigned int major,
+ unsigned int minor,
+ umode_t mode,
+ void *ops, void *info)
+{
+ struct inode *parent_inode;
+ struct dentry *dentry;
+ int err = devfs_decode(dir, name, 0, &parent_inode, &dentry);
+
+ if (!err) {
+ err = vfs_mknod(parent_inode, dentry, mode,
+ MKDEV(major, minor));
+ up(&parent_inode->i_sem);
+ if (err) {
+ printk ("AJR devfs_register(dir %p, name %s, flags 0x%x,\n\tmajor %d, minor %d, mode 0%o, ops %p, info %p)\n\tfailed, err %d.\n",
+ dir, name, flags, major, minor, mode, ops, info, err);
+ BUG_ON(err != -EEXIST); /* AJR */
+ dput(dentry);
+ }
+ }
+
+ return err ? NULL : dentry;
+
+}
+EXPORT_SYMBOL(devfs_register);
+
+void devfs_unregister (devfs_handle_t de)
+{
+ if (S_ISDIR(de->d_inode->i_mode))
+ vfs_rmdir(de->d_parent->d_inode, de);
+ else
+ vfs_unlink(de->d_parent->d_inode, de);
+}
+EXPORT_SYMBOL(devfs_unregister);
+
+void devfs_put (devfs_handle_t de)
+{
+ dput(de);
+}
+EXPORT_SYMBOL(devfs_put);
+
+int devfs_mk_symlink (devfs_handle_t dir, const char *name,
+ unsigned int flags, const char *link,
+ devfs_handle_t *handle, void *info)
+{
+ struct inode *parent_inode;
+ struct dentry *dentry;
+ int err = devfs_decode(dir, name, 0, &parent_inode, &dentry);
+
+ if (!err) {
+ err = vfs_symlink(parent_inode, dentry, link);
+ up(&parent_inode->i_sem);
+ }
+
+ dput(dentry);
+ return err;
+}
+EXPORT_SYMBOL(devfs_mk_symlink);
+
+devfs_handle_t devfs_mk_dir (devfs_handle_t dir, const char *name, void *info)
+{
+ struct inode *parent_inode;
+ struct dentry *dentry;
+ int err = devfs_decode(dir, name, 1, &parent_inode, &dentry);
+
+ if (!err) {
+ err = vfs_mkdir(parent_inode, dentry, 0644);
+ up(&parent_inode->i_sem);
+ if (err) {
+ BUG_ON (err != -EEXIST); /* AJR */
+ dput(dentry);
+ }
+ }
+ else
+ BUG(); /* AJR */
+ return err ? NULL : dentry;
+}
+EXPORT_SYMBOL(devfs_mk_dir);
+
+/* From fs/devfs/base.c: */
+void devfs_remove(const char *fmt, ...)
+{
+ char buf[64];
+ va_list args;
+ int len;
+ struct nameidata nd;
+ int err;
+
+ va_start(args, fmt);
+ len = vsnprintf(buf, sizeof(buf), fmt, args);
+ if (len >= sizeof(buf)) {
+ BUG();
+ return;
+ }
+
+ buf[sizeof(buf)-1] = '\0';
+
+ memset(&nd, 0, sizeof(nd));
+ nd.mnt = devfs2_vfsmount;
+ nd.dentry = devfs2_vfsmount->mnt_sb->s_root;
+
+ spin_lock(&dcache_lock);
+ err = link_path_walk(buf, &nd);
+ if (!err) {
+ devfs_unregister(nd.dentry);
+ devfs_put(nd.dentry);
+ }
+ else
+ printk ("AJR devfs_remove: link_path_walk(buf %s, len %d) "
+ "returned err %d.\n", buf, len, err);
+
+}
+
+EXPORT_SYMBOL(devfs_remove);
+
+int devfs_only(void)
+{
+ return 0;
+}
+
+void __init mount_devfs_fs (void)
+{
+#ifdef CONFIG_DEVFS_MOUNT
+ int err;
+
+ err = do_mount ("none", "/dev", "devfs", 0, "");
+ if (err == 0) printk (KERN_INFO "Mounted devfs on /dev\n");
+ else printk ("(): unable to mount devfs2, err: %d\n", err);
+#endif
+} /* End Function mount_devfs_fs */
+
+
+static int path_len (struct dentry *de, struct dentry *root)
+{
+ int len = 0;
+ while (de != root) {
+ len += de->d_name.len + 1; /* count the '/' */
+ de = de->d_parent;
+ }
+ return len; /* -1 because we omit the leading '/',
+ +1 because we include trailing '\0' */
+}
+
+int devfs_generate_path (devfs_handle_t de, char *path, int buflen)
+{
+ struct dentry *devfs_root;
+ int len;
+ char *path_orig = path;
+
+ if (de == NULL) {
+ BUG();
+ return -EINVAL;
+ }
+
+ devfs_root = devfs2_vfsmount->mnt_sb->s_root;
+
+ if (de == devfs_root) {
+ BUG();
+ return -EINVAL;
+ }
+
+ spin_lock(&dcache_lock);
+ len = path_len(de, devfs_root);
+ if (len > buflen) {
+ spin_unlock(&dcache_lock);
+ BUG();
+ return -ENAMETOOLONG;
+ }
+
+ path += len - 1;
+ *path = '\0';
+
+ for (;;) {
+ path -= de->d_name.len;
+ memcpy(path, de->d_name.name, de->d_name.len);
+ de = de->d_parent;
+ if (de == devfs_root)
+ break;
+ *(--path) = '/';
+ }
+
+ spin_unlock(&dcache_lock);
+
+ BUG_ON(path != path_orig);
+
+ return 0;
+}
+
+int devfs_set_file_size (devfs_handle_t de, unsigned long size)
+{
+ /* STUB */
+ BUG();
+ return -1;
+}
--- linux-2.5.53/fs/mini-devfs/numspace.c 1969-12-31 16:00:00.000000000 -0800
+++ linux/fs/mini-devfs/numspace.c 2002-12-31 22:39:35.000000000 -0800
@@ -0,0 +1,100 @@
+/* numspace operations copied from devfs/util.c, which have the following
+ copyright notice:
+
+ Copyright (C) 1998-2002 Richard Gooch
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Richard Gooch may be reached by email at rgooch@atnf.csiro.au
+ The postal address is:
+ Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
+*/
+
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/devfs_fs_kernel.h>
+
+/**
+ * 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;
+
+ /* 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)
+ {
+ void *bits;
+
+ 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 ("(): number %d was already free\n", number);
+} /* End Function devfs_dealloc_unique_number */
+EXPORT_SYMBOL(devfs_dealloc_unique_number);
\
 
 \ /
  Last update: 2005-03-22 13:32    [W:0.028 / U:0.400 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site