Linux Devfs (Device File System) FAQ
Richard Gooch
-24-JAN-2002
+4-APR-2002
Document languages:
add the following lines to your /etc/devfsd.conf file:
-REGISTER ^pt[sy]/.* IGNORE
-CHANGE ^pt[sy]/.* IGNORE
+REGISTER ^pt[sy] IGNORE
+CREATE ^pt[sy] IGNORE
+CHANGE ^pt[sy] IGNORE
+DELETE ^pt[sy] IGNORE
REGISTER .* COPY /dev-state/$devname $devpath
-CHANGE .* COPY $devpath /dev-state/$devname
CREATE .* COPY $devpath /dev-state/$devname
+CHANGE .* COPY $devpath /dev-state/$devname
+DELETE .* CFUNCTION GLOBAL unlink /dev-state/$devname
+RESTORE /dev-state
+Note that the sample devfsd.conf file contains these lines,
+as well as other sample configurations you may find useful. See the
+devfsd distribution
reboot.
(for example, by starting with /etc/fstab), and then limiting the
compatibility entries that devfsd creates.
-MAKE SURE YOU INSTALL DEVFSD BEFORE YOU BOOT A DEVFS-ENABLED KERNEL!
+IF YOU CONFIGURE TO MOUNT DEVFS AT BOOT, MAKE SURE YOU INSTALL DEVFSD
+BEFORE YOU BOOT A DEVFS-ENABLED KERNEL!
Now that devfs has gone into the 2.3.46 kernel, I'm getting a lot of
reports back. Many of these are because people are trying to run
the existence of the entry should be relied upon.
+When I start devfsd, I see the error:
+Error opening file: ".devfsd" No such file or directory?
+
+This means that devfs is not mounted. Make sure you have devfs mounted.
+
+
+How do I mount devfs?
+
+First make sure you have devfs compiled into your kernel (see
+above). Then you will either need to:
+
+set CONFIG_DEVFS_MOUNT=y in your kernel config
+pass devfs=mount to your boot loader
+mount devfs manually in your boot scripts with:
+mount -t none devfs /dev
+
+
+
+make sure you have enabled debugging output when configuring your
+kernel. You will need to set (at least) the following config options:
+
+CONFIG_DEVFS_DEBUG=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_SLAB=y
+
+
+
please make sure you have the latest devfs patches applied. The
latest kernel version might not have the latest devfs patches applied
yet (Linus is very busy)
save a copy of your complete kernel logs (preferably by
using the dmesg programme) for later inclusion in your bug
report. You may need to use the -s switch to increase the
-internal buffer size so you can capture all the boot messages
+internal buffer size so you can capture all the boot messages.
+Don't edit or trim the dmesg output
+
+
try booting with devfs=dall passed to the kernel boot
A Korean translation by viatoris@nownuri.net is available at
-http://viatoris.new21.org/devfs/devfs.html
+http://your.destiny.pe.kr/devfs/devfs.html
Added KERN_* to remaining messages.
Cleaned up declaration of <stat_read>.
v1.11
+ 20020219 Richard Gooch <rgooch@atnf.csiro.au>
+ Changed <devfs_rmdir> to allow later additions if not yet empty.
+ v1.12
+ 20020406 Richard Gooch <rgooch@atnf.csiro.au>
+ Removed silently introduced calls to lock_kernel() and
+ unlock_kernel() due to recent VFS locking changes. BKL isn't
+ required in devfs.
+ v1.13
*/
#include <linux/types.h>
#include <linux/errno.h>
#include <asm/bitops.h>
#include <asm/atomic.h>
-#define DEVFS_VERSION "1.11 (20020129)"
+#define DEVFS_VERSION "1.13 (20020406)"
#define DEVFS_NAME "devfs"
case 0:
scan_dir_for_removable (parent);
err = (*filldir) (dirent, "..", 2, file->f_pos,
- parent_ino(file->f_dentry), DT_DIR);
+ parent_ino (file->f_dentry), DT_DIR);
if (err == -EINVAL) break;
if (err < 0) return err;
file->f_pos++;
up on any error */
dentry->d_op = &devfs_dops;
/* First try to get the devfs entry for this directory */
- lock_kernel();
parent = get_devfs_entry_from_vfs_inode (dir);
DPRINTK (DEBUG_I_LOOKUP, "(%s): dentry: %p parent: %p by: \"%s\"\n",
dentry->d_name.name, dentry, parent, current->comm);
- if (parent == NULL) {
- unlock_kernel();
- return ERR_PTR (-ENOENT);
- }
+ if (parent == NULL) return ERR_PTR (-ENOENT);
read_lock (&parent->u.dir.lock);
de = _devfs_search_dir (parent, dentry->d_name.name, dentry->d_name.len);
read_unlock (&parent->u.dir.lock);
if (try_modload (parent, fs_info,
dentry->d_name.name, dentry->d_name.len, &tmp) < 0)
{ /* Lookup event was not queued to devfsd */
- unlock_kernel();
d_add (dentry, NULL);
return NULL;
}
wake_up (&lookup_info.wait_queue);
write_unlock (&parent->u.dir.lock);
devfs_put (de);
- unlock_kernel();
return retval;
} /* End Function devfs_lookup */
struct inode *inode = dentry->d_inode;
struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
- lock_kernel();
de = get_devfs_entry_from_vfs_inode (inode);
DPRINTK (DEBUG_I_UNLINK, "(%s): de: %p\n", dentry->d_name.name, de);
- if (de == NULL) {
- unlock_kernel();
- return -ENOENT;
- }
- if (!de->vfs_deletable) {
- unlock_kernel();
- return -EPERM;
- }
+ if (de == NULL) return -ENOENT;
+ if (!de->vfs_deletable) return -EPERM;
write_lock (&de->parent->u.dir.lock);
unhooked = _devfs_unhook (de);
write_unlock (&de->parent->u.dir.lock);
- if (!unhooked) {
- unlock_kernel();
- return -ENOENT;
- }
+ if (!unhooked) return -ENOENT;
if ( !is_devfsd_or_child (fs_info) )
devfsd_notify_de (de, DEVFSD_NOTIFY_DELETE, inode->i_mode,
inode->i_uid, inode->i_gid, fs_info, 0);
free_dentry (de);
devfs_put (de);
- unlock_kernel();
return 0;
} /* End Function devfs_unlink */
struct inode *inode;
/* First try to get the devfs entry for this directory */
- lock_kernel();
parent = get_devfs_entry_from_vfs_inode (dir);
- if (parent == NULL) {
- unlock_kernel();
- return -ENOENT;
- }
+ if (parent == NULL) return -ENOENT;
err = devfs_do_symlink (parent, dentry->d_name.name, DEVFS_FL_NONE,
symname, &de, NULL);
DPRINTK (DEBUG_DISABLED, "(%s): errcode from <devfs_do_symlink>: %d\n",
dentry->d_name.name, err);
- if (err < 0) {
- unlock_kernel();
- return err;
- }
+ if (err < 0) return err;
de->vfs_deletable = TRUE;
de->inode.uid = current->euid;
de->inode.gid = current->egid;
de->inode.atime = CURRENT_TIME;
de->inode.mtime = CURRENT_TIME;
de->inode.ctime = CURRENT_TIME;
- if ( ( inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry) ) == NULL ) {
- unlock_kernel();
+ if ( ( inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry) ) == NULL )
return -ENOMEM;
- }
DPRINTK (DEBUG_DISABLED, "(%s): new VFS inode(%u): %p dentry: %p\n",
dentry->d_name.name, de->inode.ino, inode, dentry);
d_instantiate (dentry, inode);
if ( !is_devfsd_or_child (fs_info) )
devfsd_notify_de (de, DEVFSD_NOTIFY_CREATE, inode->i_mode,
inode->i_uid, inode->i_gid, fs_info, 0);
- unlock_kernel();
return 0;
} /* End Function devfs_symlink */
struct inode *inode;
mode = (mode & ~S_IFMT) | S_IFDIR; /* VFS doesn't pass S_IFMT part */
- lock_kernel();
parent = get_devfs_entry_from_vfs_inode (dir);
- if (parent == NULL) {
- unlock_kernel();
- return -ENOENT;
- }
+ if (parent == NULL) return -ENOENT;
de = _devfs_alloc_entry (dentry->d_name.name, dentry->d_name.len, mode);
- if (!de) {
- unlock_kernel();
- return -ENOMEM;
- }
+ if (!de) return -ENOMEM;
de->vfs_deletable = TRUE;
- if ( ( err = _devfs_append_entry (parent, de, FALSE, NULL) ) != 0 ) {
- unlock_kernel();
+ if ( ( err = _devfs_append_entry (parent, de, FALSE, NULL) ) != 0 )
return err;
- }
de->inode.uid = current->euid;
de->inode.gid = current->egid;
de->inode.atime = CURRENT_TIME;
de->inode.mtime = CURRENT_TIME;
de->inode.ctime = CURRENT_TIME;
- if ( ( inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry) ) == NULL ) {
- unlock_kernel();
+ if ( ( inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry) ) == NULL )
return -ENOMEM;
- }
DPRINTK (DEBUG_DISABLED, "(%s): new VFS inode(%u): %p dentry: %p\n",
dentry->d_name.name, de->inode.ino, inode, dentry);
d_instantiate (dentry, inode);
if ( !is_devfsd_or_child (fs_info) )
devfsd_notify_de (de, DEVFSD_NOTIFY_CREATE, inode->i_mode,
inode->i_uid, inode->i_gid, fs_info, 0);
- unlock_kernel();
return 0;
} /* End Function devfs_mkdir */
struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
struct inode *inode = dentry->d_inode;
- /* WTF??? */
if (dir->i_sb->u.generic_sbp != inode->i_sb->u.generic_sbp) return -EINVAL;
- lock_kernel();
de = get_devfs_entry_from_vfs_inode (inode);
- if (de == NULL) {
- unlock_kernel();
- return -ENOENT;
- }
- if ( !S_ISDIR (de->mode) ) {
- unlock_kernel();
- return -ENOTDIR;
- }
- if (!de->vfs_deletable) {
- unlock_kernel();
- return -EPERM;
- }
- /* First ensure the directory is empty and will stay thay way */
+ if (de == NULL) return -ENOENT;
+ if ( !S_ISDIR (de->mode) ) return -ENOTDIR;
+ if (!de->vfs_deletable) return -EPERM;
+ /* First ensure the directory is empty and will stay that way */
write_lock (&de->u.dir.lock);
- de->u.dir.no_more_additions = TRUE;
if (de->u.dir.first) err = -ENOTEMPTY;
+ else de->u.dir.no_more_additions = TRUE;
write_unlock (&de->u.dir.lock);
- if (err) {
- unlock_kernel();
- return err;
- }
+ if (err) return err;
/* Now unhook the directory from it's parent */
write_lock (&de->parent->u.dir.lock);
if ( !_devfs_unhook (de) ) err = -ENOENT;
write_unlock (&de->parent->u.dir.lock);
- if (err) {
- unlock_kernel();
- return err;
- }
+ if (err) return err;
if ( !is_devfsd_or_child (fs_info) )
devfsd_notify_de (de, DEVFSD_NOTIFY_DELETE, inode->i_mode,
inode->i_uid, inode->i_gid, fs_info, 0);
free_dentry (de);
devfs_put (de);
- unlock_kernel();
return 0;
} /* End Function devfs_rmdir */
DPRINTK (DEBUG_I_MKNOD, "(%s): mode: 0%o dev: %d\n",
dentry->d_name.name, mode, rdev);
- lock_kernel();
parent = get_devfs_entry_from_vfs_inode (dir);
- if (parent == NULL) {
- unlock_kernel();
- return -ENOENT;
- }
+ if (parent == NULL) return -ENOENT;
de = _devfs_alloc_entry (dentry->d_name.name, dentry->d_name.len, mode);
- if (!de) {
- unlock_kernel();
- return -ENOMEM;
- }
+ if (!de) return -ENOMEM;
de->vfs_deletable = TRUE;
if ( S_ISBLK (mode) || S_ISCHR (mode) )
{
de->u.fcb.u.device.major = MAJOR (rdev);
de->u.fcb.u.device.minor = MINOR (rdev);
}
- if ( ( err = _devfs_append_entry (parent, de, FALSE, NULL) ) != 0 ) {
- unlock_kernel();
+ if ( ( err = _devfs_append_entry (parent, de, FALSE, NULL) ) != 0 )
return err;
- }
de->inode.uid = current->euid;
de->inode.gid = current->egid;
de->inode.atime = CURRENT_TIME;
de->inode.mtime = CURRENT_TIME;
de->inode.ctime = CURRENT_TIME;
- if ( ( inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry) ) == NULL ) {
- unlock_kernel();
+ if ( ( inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry) ) == NULL )
return -ENOMEM;
- }
DPRINTK (DEBUG_I_MKNOD, ": new VFS inode(%u): %p dentry: %p\n",
de->inode.ino, inode, dentry);
d_instantiate (dentry, inode);
if ( !is_devfsd_or_child (fs_info) )
devfsd_notify_de (de, DEVFSD_NOTIFY_CREATE, inode->i_mode,
inode->i_uid, inode->i_gid, fs_info, 0);
- unlock_kernel();
return 0;
} /* End Function devfs_mknod */
PRINTK ("(): get root inode failed\n");
if (root_inode) iput (root_inode);
return -EINVAL;
-} /* End Function devfs_read_super */
+} /* End Function devfs_fill_super */
-static struct super_block *devfs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+static struct super_block *devfs_get_sb (struct file_system_type *fs_type,
+ int flags, char *dev_name, void *data)
{
- return get_sb_single(fs_type, flags, data, devfs_fill_super);
+ return get_sb_single (fs_type, flags, data, devfs_fill_super);
}
-static struct file_system_type devfs_fs_type = {
- name: DEVFS_NAME,
- get_sb: devfs_get_sb,
- kill_sb: kill_anon_super,
+static struct file_system_type devfs_fs_type =
+{
+ name: DEVFS_NAME,
+ get_sb: devfs_get_sb,
+ kill_sb: kill_anon_super,
};
/* File operations for devfsd follow */
/* devfs (Device FileSystem) utilities.
- Copyright (C) 1999-2001 Richard Gooch
+ Copyright (C) 1999-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
20010818 Richard Gooch <rgooch@atnf.csiro.au>
Updated major masks up to Linus' "no new majors" proclamation.
Block: were 126 now 122 free, char: were 26 now 19 free.
+ 20020324 Richard Gooch <rgooch@atnf.csiro.au>
+ Fixed bug in <devfs_alloc_unique_number>: was clearing beyond
+ bitfield.
+ 20020326 Richard Gooch <rgooch@atnf.csiro.au>
+ Fixed bitfield data type for <devfs_*alloc_devnum>.
+ Made major bitfield type and initialiser 64 bit safe.
*/
#include <linux/module.h>
#include <linux/init.h>
struct major_list
{
spinlock_t lock;
- __u32 bits[8];
+ unsigned long bits[256 / BITS_PER_LONG];
};
+#if BITS_PER_LONG == 32
+# define INITIALISER64(low,high) (low), (high)
+#else
+# define INITIALISER64(low,high) ( (high) << 32 | (low) )
+#endif
/* Block majors already assigned:
0-3, 7-9, 11-63, 65-99, 101-113, 120-127, 199, 201, 240-255
*/
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 */
+ {INITIALISER64 (0xfffffb8f, 0xffffffff), /* Majors 0-31, 32-63 */
+ INITIALISER64 (0xfffffffe, 0xff03ffef), /* Majors 64-95, 96-127 */
+ INITIALISER64 (0x00000000, 0x00000000), /* Majors 128-159, 160-191 */
+ INITIALISER64 (0x00000280, 0xffff0000), /* Majors 192-223, 224-255 */
+ }
};
/* Char majors already assigned:
*/
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 */
+ {INITIALISER64 (0xfffffeff, 0xffffffff), /* Majors 0-31, 32-63 */
+ INITIALISER64 (0xffffffff, 0xffffffff), /* Majors 64-95, 96-127 */
+ INITIALISER64 (0x7cffffff, 0xffffffff), /* Majors 128-159, 160-191 */
+ INITIALISER64 (0x3f0fffff, 0xffff007f), /* Majors 192-223, 224-255 */
+ }
};
struct minor_list
{
int major;
- __u32 bits[8];
+ unsigned long bits[256 / BITS_PER_LONG];
struct minor_list *next;
};
if (minor >= 256) continue;
__set_bit (minor, entry->bits);
up (semaphore);
- return mk_kdev(entry->major, minor);
+ return mk_kdev (entry->major, minor);
}
/* Need to allocate a new major */
if ( ( entry = kmalloc (sizeof *entry, GFP_KERNEL) ) == NULL )
else list->last->next = entry;
list->last = entry;
up (semaphore);
- return mk_kdev(entry->major, 0);
+ return mk_kdev (entry->major, 0);
} /* End Function devfs_alloc_devnum */
EXPORT_SYMBOL(devfs_alloc_devnum);
struct device_list *list;
struct minor_list *entry;
- if (kdev_none(devnum)) return;
+ if ( kdev_none (devnum) ) return;
if (type == DEVFS_SPECIAL_CHR)
{
semaphore = &char_semaphore;
{
int number;
unsigned int length;
- __u32 *bits;
/* Get around stupid lack of semaphore initialiser */
spin_lock (&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 )