📄 base.c
字号:
19991107 Richard Gooch <rgooch@atnf.csiro.au> Support new "disc" naming scheme in <get_removable_partition>. Allow NULL fops in <devfs_register>. Work sponsored by SGI. v0.85 19991110 Richard Gooch <rgooch@atnf.csiro.au> Fall back to major table if NULL fops given to <devfs_register>. Work sponsored by SGI. v0.86 19991204 Richard Gooch <rgooch@atnf.csiro.au> Support fifos when unregistering. Work sponsored by SGI. v0.87 19991209 Richard Gooch <rgooch@atnf.csiro.au> Removed obsolete DEVFS_ FL_COMPAT and DEVFS_ FL_TOLERANT flags. Work sponsored by SGI. v0.88 19991214 Richard Gooch <rgooch@atnf.csiro.au> Removed kmod support. Work sponsored by SGI. v0.89 19991216 Richard Gooch <rgooch@atnf.csiro.au> Improved debugging in <get_vfs_inode>. Ensure dentries created by devfsd will be cleaned up. Work sponsored by SGI. v0.90 19991223 Richard Gooch <rgooch@atnf.csiro.au> Created <devfs_get_name>. Work sponsored by SGI. v0.91 20000203 Richard Gooch <rgooch@atnf.csiro.au> Ported to kernel 2.3.42. Removed <devfs_fill_file>. Work sponsored by SGI. v0.92 20000306 Richard Gooch <rgooch@atnf.csiro.au> Added DEVFS_FL_NO_PERSISTENCE flag. Removed unnecessary call to <update_devfs_inode_from_entry> in <devfs_readdir>. Work sponsored by SGI. v0.93 20000413 Richard Gooch <rgooch@atnf.csiro.au> Set inode->i_size to correct size for symlinks. 20000414 Richard Gooch <rgooch@atnf.csiro.au> Only give lookup() method to directories to comply with new VFS assumptions. Work sponsored by SGI. 20000415 Richard Gooch <rgooch@atnf.csiro.au> Remove unnecessary tests in symlink methods. Don't kill existing block ops in <devfs_read_inode>. Work sponsored by SGI. v0.94 20000424 Richard Gooch <rgooch@atnf.csiro.au> Don't create missing directories in <devfs_find_handle>. Work sponsored by SGI. v0.95 20000430 Richard Gooch <rgooch@atnf.csiro.au> Added CONFIG_DEVFS_MOUNT. Work sponsored by SGI. v0.96 20000608 Richard Gooch <rgooch@atnf.csiro.au> Disabled multi-mount capability (use VFS bindings instead). Work sponsored by SGI. v0.97 20000610 Richard Gooch <rgooch@atnf.csiro.au> Switched to FS_SINGLE to disable multi-mounts. 20000612 Richard Gooch <rgooch@atnf.csiro.au> Removed module support. Removed multi-mount code. Removed compatibility macros: VFS has changed too much. Work sponsored by SGI. v0.98 20000614 Richard Gooch <rgooch@atnf.csiro.au> Merged devfs inode into devfs entry. Work sponsored by SGI. v0.99 20000619 Richard Gooch <rgooch@atnf.csiro.au> Removed dead code in <devfs_register> which used to call <free_dentries>. Work sponsored by SGI. v0.100 20000621 Richard Gooch <rgooch@atnf.csiro.au> Changed interface to <devfs_register>. Work sponsored by SGI. v0.101 20000622 Richard Gooch <rgooch@atnf.csiro.au> Simplified interface to <devfs_mk_symlink> and <devfs_mk_dir>. Simplified interface to <devfs_find_handle>. Work sponsored by SGI. v0.102*/#include <linux/types.h>#include <linux/errno.h>#include <linux/sched.h>#include <linux/tty.h>#include <linux/timer.h>#include <linux/config.h>#include <linux/kernel.h>#include <linux/wait.h>#include <linux/string.h>#include <linux/malloc.h>#include <linux/ioport.h>#include <linux/delay.h>#include <linux/ctype.h>#include <linux/mm.h>#include <linux/module.h>#include <linux/init.h>#include <linux/locks.h>#include <linux/kdev_t.h>#include <linux/devfs_fs.h>#include <linux/devfs_fs_kernel.h>#include <linux/smp_lock.h>#include <linux/smp.h>#include <linux/version.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/processor.h>#include <asm/system.h>#include <asm/pgtable.h>#include <asm/segment.h>#include <asm/bitops.h>#include <asm/atomic.h>#define DEVFS_VERSION "0.102 (20000622)"#define DEVFS_NAME "devfs"#define INODE_TABLE_INC 250#define FIRST_INODE 1#define STRING_LENGTH 256#define MIN_DEVNUM 36864 /* Use major numbers 144 */#define MAX_DEVNUM 61439 /* through 239, inclusive */#ifndef TRUE# define TRUE 1# define FALSE 0#endif#define IS_HIDDEN(de) (( ((de)->hide && !is_devfsd_or_child(fs_info)) || (!(de)->registered&& !(de)->show_unreg)))#define DEBUG_NONE 0x00000#define DEBUG_MODULE_LOAD 0x00001#define DEBUG_REGISTER 0x00002#define DEBUG_UNREGISTER 0x00004#define DEBUG_SET_FLAGS 0x00008#define DEBUG_S_PUT 0x00010#define DEBUG_I_LOOKUP 0x00020#define DEBUG_I_CREATE 0x00040#define DEBUG_I_READ 0x00080#define DEBUG_I_WRITE 0x00100#define DEBUG_I_UNLINK 0x00200#define DEBUG_I_RLINK 0x00400#define DEBUG_I_FLINK 0x00800#define DEBUG_I_MKNOD 0x01000#define DEBUG_F_READDIR 0x02000#define DEBUG_D_DELETE 0x04000#define DEBUG_D_RELEASE 0x08000#define DEBUG_D_IPUT 0x10000#define DEBUG_ALL (DEBUG_MODULE_LOAD | DEBUG_REGISTER | \ DEBUG_SET_FLAGS | DEBUG_I_LOOKUP | \ DEBUG_I_UNLINK | DEBUG_I_MKNOD | \ DEBUG_D_RELEASE | DEBUG_D_IPUT)#define DEBUG_DISABLED DEBUG_NONE#define OPTION_NONE 0x00#define OPTION_SHOW 0x01#define OPTION_NOMOUNT 0x02#define OPTION_ONLY 0x04#define OOPS(format, args...) {printk (format, ## args); \ printk ("Forcing Oops\n"); \ BUG();}struct directory_type{ struct devfs_entry *first; struct devfs_entry *last; unsigned int num_removable;};struct file_type{ unsigned long size;};struct device_type{ unsigned short major; unsigned short minor;};struct fcb_type /* File, char, block type */{ uid_t default_uid; gid_t default_gid; void *ops; union { struct file_type file; struct device_type device; } u; unsigned char auto_owner:1; unsigned char aopen_notify:1; unsigned char removable:1; /* Belongs in device_type, but save space */ unsigned char open:1; /* Not entirely correct */};struct symlink_type{ unsigned int length; /* Not including the NULL-termimator */ char *linkname; /* This is NULL-terminated */};struct fifo_type{ uid_t uid; gid_t gid;};struct devfs_inode /* This structure is for "persistent" inode storage */{ time_t atime; time_t mtime; time_t ctime; unsigned int ino; /* Inode number as seen in the VFS */ struct dentry *dentry; umode_t mode; uid_t uid; gid_t gid; nlink_t nlink;};struct devfs_entry{ void *info; union { struct directory_type dir; struct fcb_type fcb; struct symlink_type symlink; struct fifo_type fifo; } u; struct devfs_entry *prev; /* Previous entry in the parent directory */ struct devfs_entry *next; /* Next entry in the parent directory */ struct devfs_entry *parent; /* The parent directory */ struct devfs_entry *slave; /* Another entry to unregister */ struct devfs_inode inode; umode_t mode; unsigned short namelen; /* I think 64k+ filenames are a way off... */ unsigned char registered:1; unsigned char show_unreg:1; unsigned char hide:1; unsigned char no_persistence:1; char name[1]; /* This is just a dummy: the allocated array is bigger. This is NULL-terminated */};/* The root of the device tree */static struct devfs_entry *root_entry;struct devfsd_buf_entry{ void *data; unsigned int type; umode_t mode; uid_t uid; gid_t gid;};struct fs_info /* This structure is for each mounted devfs */{ unsigned int num_inodes; /* Number of inodes created */ unsigned int table_size; /* Size of the inode pointer table */ struct devfs_entry **table; struct super_block *sb; volatile struct devfsd_buf_entry *devfsd_buffer; volatile unsigned int devfsd_buf_in; volatile unsigned int devfsd_buf_out; volatile int devfsd_sleeping; volatile int devfsd_buffer_in_use; volatile struct task_struct *devfsd_task; volatile struct file *devfsd_file; volatile unsigned long devfsd_event_mask; atomic_t devfsd_overrun_count; wait_queue_head_t devfsd_wait_queue; wait_queue_head_t revalidate_wait_queue;};static struct fs_info fs_info;static unsigned int next_devnum_char = MIN_DEVNUM;static unsigned int next_devnum_block = MIN_DEVNUM;static const int devfsd_buf_size = PAGE_SIZE / sizeof(struct devfsd_buf_entry);#ifdef CONFIG_DEVFS_DEBUGstatic unsigned int devfs_debug_init __initdata = DEBUG_NONE;static unsigned int devfs_debug = DEBUG_NONE;#endif#ifdef CONFIG_DEVFS_MOUNTstatic unsigned int boot_options = OPTION_NONE;#elsestatic unsigned int boot_options = OPTION_NOMOUNT;#endif/* Forward function declarations */static struct devfs_entry *search_for_entry (struct devfs_entry *dir, const char *name, unsigned int namelen, int mkdir, int mkfile, int *is_new, int traverse_symlink);static ssize_t devfsd_read (struct file *file, char *buf, size_t len, loff_t *ppos);static int devfsd_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);static int devfsd_close (struct inode *inode, struct file *file);/* Devfs daemon file operations */static struct file_operations devfsd_fops ={ read: devfsd_read, ioctl: devfsd_ioctl, release: devfsd_close,};/* Support functions follow *//** * search_for_entry_in_dir - Search for a devfs entry inside another devfs entry. * @parent: The parent devfs entry. * @name: The name of the entry. * @namelen: The number of characters in @name. * @traverse_symlink: If %TRUE then the entry is traversed if it is a symlink. * * Search for a devfs entry inside another devfs entry and returns a pointer * to the entry on success, else %NULL. */static struct devfs_entry *search_for_entry_in_dir (struct devfs_entry *parent, const char *name, unsigned int namelen, int traverse_symlink){ struct devfs_entry *curr; if ( !S_ISDIR (parent->mode) ) { printk ("%s: entry is not a directory\n", DEVFS_NAME); return NULL; } for (curr = parent->u.dir.first; curr != NULL; curr = curr->next) { if (curr->namelen != namelen) continue; if (memcmp (curr->name, name, namelen) == 0) break; /* Not found: try the next one */ } if (curr == NULL) return NULL; if (!S_ISLNK (curr->mode) || !traverse_symlink) return curr; /* Need to follow the link: this is a stack chomper */ return search_for_entry (parent, curr->u.symlink.linkname, curr->u.symlink.length, FALSE, FALSE, NULL, TRUE);} /* End Function search_for_entry_in_dir */static struct devfs_entry *create_entry (struct devfs_entry *parent, const char *name,unsigned int namelen){ struct devfs_entry *new, **table; /* First ensure table size is enough */ if (fs_info.num_inodes >= fs_info.table_size) { if ( ( table = kmalloc (sizeof *table * (fs_info.table_size + INODE_TABLE_INC), GFP_KERNEL) ) == NULL ) return NULL; fs_info.table_size += INODE_TABLE_INC;#ifdef CONFIG_DEVFS_DEBUG if (devfs_debug & DEBUG_I_CREATE) printk ("%s: create_entry(): grew inode table to: %u entries\n", DEVFS_NAME, fs_info.table_size);#endif if (fs_info.table) { memcpy (table, fs_info.table, sizeof *table *fs_info.num_inodes); kfree (fs_info.table); } fs_info.table = table;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -