base.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,003 行 · 第 1/5 页

C
2,003
字号
struct devfsd_buf_entry {	struct devfs_entry *de;	/*  The name is generated with this         */	unsigned short type;	/*  The type of event                       */	umode_t mode;	uid_t uid;	gid_t gid;	struct devfsd_buf_entry *next;};struct fs_info {		/*  This structure is for the mounted devfs  */	struct super_block *sb;	spinlock_t devfsd_buffer_lock;	/*  Lock when inserting/deleting events  */	struct devfsd_buf_entry *devfsd_first_event;	struct devfsd_buf_entry *devfsd_last_event;	volatile int devfsd_sleeping;	volatile struct task_struct *devfsd_task;	volatile pid_t devfsd_pgrp;	volatile struct file *devfsd_file;	struct devfsd_notify_struct *devfsd_info;	volatile unsigned long devfsd_event_mask;	atomic_t devfsd_overrun_count;	wait_queue_head_t devfsd_wait_queue;	/*  Wake devfsd on input       */	wait_queue_head_t revalidate_wait_queue;	/*  Wake when devfsd sleeps    */};static struct fs_info fs_info = {.devfsd_buffer_lock = SPIN_LOCK_UNLOCKED };static kmem_cache_t *devfsd_buf_cache;#ifdef CONFIG_DEVFS_DEBUGstatic unsigned int devfs_debug_init __initdata = DEBUG_NONE;static unsigned int devfs_debug = DEBUG_NONE;static spinlock_t stat_lock = SPIN_LOCK_UNLOCKED;static unsigned int stat_num_entries;static unsigned int stat_num_bytes;#endifstatic unsigned char poison_array[8] =    { 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a };#ifdef CONFIG_DEVFS_MOUNTstatic unsigned int boot_options = OPTION_MOUNT;#elsestatic unsigned int boot_options = OPTION_NONE;#endif/*  Forward function declarations  */static devfs_handle_t _devfs_walk_path(struct devfs_entry *dir,				       const char *name, int namelen,				       int traverse_symlink);static ssize_t devfsd_read(struct file *file, char __user *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);#ifdef CONFIG_DEVFS_DEBUGstatic ssize_t stat_read(struct file *file, char __user *buf, size_t len,			 loff_t * ppos);static struct file_operations stat_fops = {	.open = nonseekable_open,	.read = stat_read,};#endif/*  Devfs daemon file operations  */static struct file_operations devfsd_fops = {	.open = nonseekable_open,	.read = devfsd_read,	.ioctl = devfsd_ioctl,	.release = devfsd_close,};/*  Support functions follow  *//** *	devfs_get - Get a reference to a devfs entry. *	@de:  The devfs entry. */static struct devfs_entry *devfs_get(struct devfs_entry *de){	VERIFY_ENTRY(de);	if (de)		atomic_inc(&de->refcount);	return de;}				/*  End Function devfs_get  *//** *	devfs_put - Put (release) a reference to a devfs entry. *	@de:  The handle to the devfs entry. */static void devfs_put(devfs_handle_t de){	if (!de)		return;	VERIFY_ENTRY(de);	if (de->info == POISON_PTR)		OOPS("(%p): poisoned pointer\n", de);	if (!atomic_dec_and_test(&de->refcount))		return;	if (de == root_entry)		OOPS("(%p): root entry being freed\n", de);	DPRINTK(DEBUG_FREE, "(%s): de: %p, parent: %p \"%s\"\n",		de->name, de, de->parent,		de->parent ? de->parent->name : "no parent");	if (S_ISLNK(de->mode))		kfree(de->u.symlink.linkname);	WRITE_ENTRY_MAGIC(de, 0);#ifdef CONFIG_DEVFS_DEBUG	spin_lock(&stat_lock);	--stat_num_entries;	stat_num_bytes -= sizeof *de + de->namelen;	if (S_ISLNK(de->mode))		stat_num_bytes -= de->u.symlink.length + 1;	spin_unlock(&stat_lock);#endif	de->info = POISON_PTR;	kfree(de);}				/*  End Function devfs_put  *//** *	_devfs_search_dir - Search for a devfs entry in a directory. *	@dir:  The directory to search. *	@name:  The name of the entry to search for. *	@namelen:  The number of characters in @name. * *  Search for a devfs entry in a directory and returns a pointer to the entry *   on success, else %NULL. The directory must be locked already. *   An implicit devfs_get() is performed on the returned entry. */static struct devfs_entry *_devfs_search_dir(struct devfs_entry *dir,					     const char *name,					     unsigned int namelen){	struct devfs_entry *curr;	if (!S_ISDIR(dir->mode)) {		PRINTK("(%s): not a directory\n", dir->name);		return NULL;	}	for (curr = dir->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  */	}	return devfs_get(curr);}				/*  End Function _devfs_search_dir  *//** *	_devfs_alloc_entry - Allocate a devfs entry. *	@name:     the name of the entry *	@namelen:  the number of characters in @name *      @mode:     the mode for the entry * *  Allocate a devfs entry and returns a pointer to the entry on success, else *   %NULL. */static struct devfs_entry *_devfs_alloc_entry(const char *name,					      unsigned int namelen,					      umode_t mode){	struct devfs_entry *new;	static unsigned long inode_counter = FIRST_INODE;	static spinlock_t counter_lock = SPIN_LOCK_UNLOCKED;	if (name && (namelen < 1))		namelen = strlen(name);	if ((new = kmalloc(sizeof *new + namelen, GFP_KERNEL)) == NULL)		return NULL;	memset(new, 0, sizeof *new + namelen);	/*  Will set '\0' on name  */	new->mode = mode;	if (S_ISDIR(mode))		rwlock_init(&new->u.dir.lock);	atomic_set(&new->refcount, 1);	spin_lock(&counter_lock);	new->inode.ino = inode_counter++;	spin_unlock(&counter_lock);	if (name)		memcpy(new->name, name, namelen);	new->namelen = namelen;	WRITE_ENTRY_MAGIC(new, MAGIC_VALUE);#ifdef CONFIG_DEVFS_DEBUG	spin_lock(&stat_lock);	++stat_num_entries;	stat_num_bytes += sizeof *new + namelen;	spin_unlock(&stat_lock);#endif	return new;}				/*  End Function _devfs_alloc_entry  *//** *	_devfs_append_entry - Append a devfs entry to a directory's child list. *	@dir:  The directory to add to. *	@de:  The devfs entry to append. *	@old_de: If an existing entry exists, it will be written here. This may *		 be %NULL. An implicit devfs_get() is performed on this entry. * *  Append a devfs entry to a directory's list of children, checking first to *   see if an entry of the same name exists. The directory will be locked. *   The value 0 is returned on success, else a negative error code. *   On failure, an implicit devfs_put() is performed on %de. */static int _devfs_append_entry(devfs_handle_t dir, devfs_handle_t de,			       devfs_handle_t * old_de){	int retval;	if (old_de)		*old_de = NULL;	if (!S_ISDIR(dir->mode)) {		PRINTK("(%s): dir: \"%s\" is not a directory\n", de->name,		       dir->name);		devfs_put(de);		return -ENOTDIR;	}	write_lock(&dir->u.dir.lock);	if (dir->u.dir.no_more_additions)		retval = -ENOENT;	else {		struct devfs_entry *old;		old = _devfs_search_dir(dir, de->name, de->namelen);		if (old_de)			*old_de = old;		else			devfs_put(old);		if (old == NULL) {			de->parent = dir;			de->prev = dir->u.dir.last;			/*  Append to the directory's list of children  */			if (dir->u.dir.first == NULL)				dir->u.dir.first = de;			else				dir->u.dir.last->next = de;			dir->u.dir.last = de;			retval = 0;		} else			retval = -EEXIST;	}	write_unlock(&dir->u.dir.lock);	if (retval)		devfs_put(de);	return retval;}				/*  End Function _devfs_append_entry  *//** *	_devfs_get_root_entry - Get the root devfs entry. * *	Returns the root devfs entry on success, else %NULL. * *	TODO it must be called asynchronously due to the fact *	that devfs is initialized relatively late. Proper way *	is to remove module_init from init_devfs_fs and manually *	call it early enough during system init */static struct devfs_entry *_devfs_get_root_entry(void){	struct devfs_entry *new;	static spinlock_t root_lock = SPIN_LOCK_UNLOCKED;	if (root_entry)		return root_entry;	new = _devfs_alloc_entry(NULL, 0, MODE_DIR);	if (new == NULL)		return NULL;	spin_lock(&root_lock);	if (root_entry) {		spin_unlock(&root_lock);		devfs_put(new);		return root_entry;	}	root_entry = new;	spin_unlock(&root_lock);	return root_entry;}				/*  End Function _devfs_get_root_entry  *//** *	_devfs_descend - Descend down a tree using the next component name. *	@dir:  The directory to search. *	@name:  The component name to search for. *	@namelen:  The length of %name. *	@next_pos:  The position of the next '/' or '\0' is written here. * *  Descend into a directory, searching for a component. This function forms *   the core of a tree-walking algorithm. The directory will be locked. *   The devfs entry corresponding to the component is returned. If there is *   no matching entry, %NULL is returned. *   An implicit devfs_get() is performed on the returned entry. */static struct devfs_entry *_devfs_descend(struct devfs_entry *dir,					  const char *name, int namelen,					  int *next_pos){	const char *stop, *ptr;	struct devfs_entry *entry;	if ((namelen >= 3) && (strncmp(name, "../", 3) == 0)) {	/*  Special-case going to parent directory  */		*next_pos = 3;		return devfs_get(dir->parent);	}	stop = name + namelen;	/*  Search for a possible '/'  */	for (ptr = name; (ptr < stop) && (*ptr != '/'); ++ptr) ;	*next_pos = ptr - name;	read_lock(&dir->u.dir.lock);	entry = _devfs_search_dir(dir, name, *next_pos);	read_unlock(&dir->u.dir.lock);	return entry;}				/*  End Function _devfs_descend  */static devfs_handle_t _devfs_make_parent_for_leaf(struct devfs_entry *dir,						  const char *name,						  int namelen, int *leaf_pos){	int next_pos = 0;	if (dir == NULL)		dir = _devfs_get_root_entry();	if (dir == NULL)		return NULL;	devfs_get(dir);	/*  Search for possible trailing component and ignore it  */	for (--namelen; (namelen > 0) && (name[namelen] != '/'); --namelen) ;	*leaf_pos = (name[namelen] == '/') ? (namelen + 1) : 0;	for (; namelen > 0; name += next_pos, namelen -= next_pos) {		struct devfs_entry *de, *old = NULL;		if ((de =		     _devfs_descend(dir, name, namelen, &next_pos)) == NULL) {			de = _devfs_alloc_entry(name, next_pos, MODE_DIR);			devfs_get(de);			if (!de || _devfs_append_entry(dir, de, &old)) {				devfs_put(de);				if (!old || !S_ISDIR(old->mode)) {					devfs_put(old);					devfs_put(dir);					return NULL;				}				de = old;	/*  Use the existing directory  */			}		}		if (de == dir->parent) {			devfs_put(dir);			devfs_put(de);			return NULL;		}		devfs_put(dir);		dir = de;		if (name[next_pos] == '/')			++next_pos;	}	return dir;}				/*  End Function _devfs_make_parent_for_leaf  */static devfs_handle_t _devfs_prepare_leaf(devfs_handle_t * dir,					  const char *name, umode_t mode){	int namelen, leaf_pos;	struct devfs_entry *de;	namelen = strlen(name);	if ((*dir = _devfs_make_parent_for_leaf(*dir, name, namelen,						&leaf_pos)) == NULL) {		PRINTK("(%s): could not create parent path\n", name);		return NULL;	}	if ((de = _devfs_alloc_entry(name + leaf_pos, namelen - leaf_pos, mode))	    == NULL) {		PRINTK("(%s): could not allocate entry\n", name);		devfs_put(*dir);		return NULL;	}	return de;}				/*  End Function _devfs_prepare_leaf  */static devfs_handle_t _devfs_walk_path(struct devfs_entry *dir,				       const char *name, int namelen,				       int traverse_symlink){	int next_pos = 0;	if (dir == NULL)		dir = _devfs_get_root_entry();	if (dir == NULL)		return NULL;	devfs_get(dir);	for (; namelen > 0; name += next_pos, namelen -= next_pos) {		struct devfs_entry *de, *link;		if (!S_ISDIR(dir->mode)) {			devfs_put(dir);			return NULL;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?