base.c

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

C
2,003
字号
		}		if ((de =		     _devfs_descend(dir, name, namelen, &next_pos)) == NULL) {			devfs_put(dir);			return NULL;		}		if (S_ISLNK(de->mode) && traverse_symlink) {	/*  Need to follow the link: this is a stack chomper  */			/* FIXME what if it puts outside of mounted tree? */			link = _devfs_walk_path(dir, de->u.symlink.linkname,						de->u.symlink.length, TRUE);			devfs_put(de);			if (!link) {				devfs_put(dir);				return NULL;			}			de = link;		}		devfs_put(dir);		dir = de;		if (name[next_pos] == '/')			++next_pos;	}	return dir;}				/*  End Function _devfs_walk_path  *//** *	_devfs_find_entry - Find a devfs entry. *	@dir: The handle to the parent devfs directory entry. If this is %NULL the *		name is relative to the root of the devfs. *	@name: The name of the entry. This may be %NULL. *	@traverse_symlink: If %TRUE then symbolic links are traversed. * *	Returns the devfs_entry pointer on success, else %NULL. An implicit *	devfs_get() is performed. */static struct devfs_entry *_devfs_find_entry(devfs_handle_t dir,					     const char *name,					     int traverse_symlink){	unsigned int namelen = strlen(name);	if (name[0] == '/') {		/*  Skip leading pathname component  */		if (namelen < 2) {			PRINTK("(%s): too short\n", name);			return NULL;		}		for (++name, --namelen; (*name != '/') && (namelen > 0);		     ++name, --namelen) ;		if (namelen < 2) {			PRINTK("(%s): too short\n", name);			return NULL;		}		++name;		--namelen;	}	return _devfs_walk_path(dir, name, namelen, traverse_symlink);}				/*  End Function _devfs_find_entry  */static struct devfs_entry *get_devfs_entry_from_vfs_inode(struct inode *inode){	if (inode == NULL)		return NULL;	VERIFY_ENTRY((struct devfs_entry *)inode->u.generic_ip);	return inode->u.generic_ip;}				/*  End Function get_devfs_entry_from_vfs_inode  *//** *	free_dentry - Free the dentry for a device entry and invalidate inode. *	@de: The entry. * *	This must only be called after the entry has been unhooked from its *	 parent directory. */static void free_dentry(struct devfs_entry *de){	struct dentry *dentry = de->inode.dentry;	if (!dentry)		return;	spin_lock(&dcache_lock);	dget_locked(dentry);	spin_unlock(&dcache_lock);	/*  Forcefully remove the inode  */	if (dentry->d_inode != NULL)		dentry->d_inode->i_nlink = 0;	d_drop(dentry);	dput(dentry);}				/*  End Function free_dentry  *//** *	is_devfsd_or_child - Test if the current process is devfsd or one of its children. *	@fs_info: The filesystem information. * *	Returns %TRUE if devfsd or child, else %FALSE. */static int is_devfsd_or_child(struct fs_info *fs_info){	struct task_struct *p = current;	if (p == fs_info->devfsd_task)		return (TRUE);	if (process_group(p) == fs_info->devfsd_pgrp)		return (TRUE);	read_lock(&tasklist_lock);	for (; p != &init_task; p = p->real_parent) {		if (p == fs_info->devfsd_task) {			read_unlock(&tasklist_lock);			return (TRUE);		}	}	read_unlock(&tasklist_lock);	return (FALSE);}				/*  End Function is_devfsd_or_child  *//** *	devfsd_queue_empty - Test if devfsd has work pending in its event queue. *	@fs_info: The filesystem information. * *	Returns %TRUE if the queue is empty, else %FALSE. */static inline int devfsd_queue_empty(struct fs_info *fs_info){	return (fs_info->devfsd_last_event) ? FALSE : TRUE;}				/*  End Function devfsd_queue_empty  *//** *	wait_for_devfsd_finished - Wait for devfsd to finish processing its event queue. *	@fs_info: The filesystem information. * *	Returns %TRUE if no more waiting will be required, else %FALSE. */static int wait_for_devfsd_finished(struct fs_info *fs_info){	DECLARE_WAITQUEUE(wait, current);	if (fs_info->devfsd_task == NULL)		return (TRUE);	if (devfsd_queue_empty(fs_info) && fs_info->devfsd_sleeping)		return TRUE;	if (is_devfsd_or_child(fs_info))		return (FALSE);	set_current_state(TASK_UNINTERRUPTIBLE);	add_wait_queue(&fs_info->revalidate_wait_queue, &wait);	if (!devfsd_queue_empty(fs_info) || !fs_info->devfsd_sleeping)		if (fs_info->devfsd_task)			schedule();	remove_wait_queue(&fs_info->revalidate_wait_queue, &wait);	__set_current_state(TASK_RUNNING);	return (TRUE);}				/*  End Function wait_for_devfsd_finished  *//** *	devfsd_notify_de - Notify the devfsd daemon of a change. *	@de: The devfs entry that has changed. This and all parent entries will *            have their reference counts incremented if the event was queued. *	@type: The type of change. *	@mode: The mode of the entry. *	@uid: The user ID. *	@gid: The group ID. *	@fs_info: The filesystem info. * *	Returns %TRUE if an event was queued and devfsd woken up, else %FALSE. */static int devfsd_notify_de(struct devfs_entry *de,			    unsigned short type, umode_t mode,			    uid_t uid, gid_t gid, struct fs_info *fs_info){	struct devfsd_buf_entry *entry;	struct devfs_entry *curr;	if (!(fs_info->devfsd_event_mask & (1 << type)))		return (FALSE);	if ((entry = kmem_cache_alloc(devfsd_buf_cache, SLAB_KERNEL)) == NULL) {		atomic_inc(&fs_info->devfsd_overrun_count);		return (FALSE);	}	for (curr = de; curr != NULL; curr = curr->parent)		devfs_get(curr);	entry->de = de;	entry->type = type;	entry->mode = mode;	entry->uid = uid;	entry->gid = gid;	entry->next = NULL;	spin_lock(&fs_info->devfsd_buffer_lock);	if (!fs_info->devfsd_first_event)		fs_info->devfsd_first_event = entry;	if (fs_info->devfsd_last_event)		fs_info->devfsd_last_event->next = entry;	fs_info->devfsd_last_event = entry;	spin_unlock(&fs_info->devfsd_buffer_lock);	wake_up_interruptible(&fs_info->devfsd_wait_queue);	return (TRUE);}				/*  End Function devfsd_notify_de  *//** *	devfsd_notify - Notify the devfsd daemon of a change. *	@de: The devfs entry that has changed. *	@type: The type of change event. *	@wait: If TRUE, the function waits for the daemon to finish processing *		the event. */static void devfsd_notify(struct devfs_entry *de, unsigned short type){	devfsd_notify_de(de, type, de->mode, current->euid,			 current->egid, &fs_info);}static int devfs_mk_dev(dev_t dev, umode_t mode, const char *fmt, va_list args){	struct devfs_entry *dir = NULL, *de;	char buf[64];	int error, n;	n = vsnprintf(buf, sizeof(buf), fmt, args);	if (n >= sizeof(buf) || !buf[0]) {		printk(KERN_WARNING "%s: invalid format string %s\n",		       __FUNCTION__, fmt);		return -EINVAL;	}	de = _devfs_prepare_leaf(&dir, buf, mode);	if (!de) {		printk(KERN_WARNING "%s: could not prepare leaf for %s\n",		       __FUNCTION__, buf);		return -ENOMEM;	/* could be more accurate... */	}	de->u.dev = dev;	error = _devfs_append_entry(dir, de, NULL);	if (error) {		printk(KERN_WARNING "%s: could not append to parent for %s\n",		       __FUNCTION__, buf);		goto out;	}	devfsd_notify(de, DEVFSD_NOTIFY_REGISTERED);      out:	devfs_put(dir);	return error;}int devfs_mk_bdev(dev_t dev, umode_t mode, const char *fmt, ...){	va_list args;	if (!S_ISBLK(mode)) {		printk(KERN_WARNING "%s: invalide mode (%u) for %s\n",		       __FUNCTION__, mode, fmt);		return -EINVAL;	}	va_start(args, fmt);	return devfs_mk_dev(dev, mode, fmt, args);}EXPORT_SYMBOL(devfs_mk_bdev);int devfs_mk_cdev(dev_t dev, umode_t mode, const char *fmt, ...){	va_list args;	if (!S_ISCHR(mode)) {		printk(KERN_WARNING "%s: invalide mode (%u) for %s\n",		       __FUNCTION__, mode, fmt);		return -EINVAL;	}	va_start(args, fmt);	return devfs_mk_dev(dev, mode, fmt, args);}EXPORT_SYMBOL(devfs_mk_cdev);/** *	_devfs_unhook - Unhook a device entry from its parents list *	@de: The entry to unhook. * *	Returns %TRUE if the entry was unhooked, else %FALSE if it was *		previously unhooked. *	The caller must have a write lock on the parent directory. */static int _devfs_unhook(struct devfs_entry *de){	struct devfs_entry *parent;	if (!de || (de->prev == de))		return FALSE;	parent = de->parent;	if (de->prev == NULL)		parent->u.dir.first = de->next;	else		de->prev->next = de->next;	if (de->next == NULL)		parent->u.dir.last = de->prev;	else		de->next->prev = de->prev;	de->prev = de;		/*  Indicate we're unhooked                      */	de->next = NULL;	/*  Force early termination for <devfs_readdir>  */	return TRUE;}				/*  End Function _devfs_unhook  *//** *	_devfs_unregister - Unregister a device entry from its parent. *	@dir: The parent directory. *	@de: The entry to unregister. * *	The caller must have a write lock on the parent directory, which is *	unlocked by this function. */static void _devfs_unregister(struct devfs_entry *dir, struct devfs_entry *de){	int unhooked = _devfs_unhook(de);	write_unlock(&dir->u.dir.lock);	if (!unhooked)		return;	devfs_get(dir);	devfsd_notify(de, DEVFSD_NOTIFY_UNREGISTERED);	free_dentry(de);	devfs_put(dir);	if (!S_ISDIR(de->mode))		return;	while (TRUE) {		/*  Recursively unregister: this is a stack chomper  */		struct devfs_entry *child;		write_lock(&de->u.dir.lock);		de->u.dir.no_more_additions = TRUE;		child = de->u.dir.first;		VERIFY_ENTRY(child);		_devfs_unregister(de, child);		if (!child)			break;		DPRINTK(DEBUG_UNREGISTER, "(%s): child: %p  refcount: %d\n",			child->name, child, atomic_read(&child->refcount));		devfs_put(child);	}}				/*  End Function _devfs_unregister  */static int devfs_do_symlink(devfs_handle_t dir, const char *name,			    const char *link, devfs_handle_t * handle){	int err;	unsigned int linklength;	char *newlink;	struct devfs_entry *de;	if (handle != NULL)		*handle = NULL;	if (name == NULL) {		PRINTK("(): NULL name pointer\n");		return -EINVAL;	}	if (link == NULL) {		PRINTK("(%s): NULL link pointer\n", name);		return -EINVAL;	}	linklength = strlen(link);	if ((newlink = kmalloc(linklength + 1, GFP_KERNEL)) == NULL)		return -ENOMEM;	memcpy(newlink, link, linklength);	newlink[linklength] = '\0';	if ((de = _devfs_prepare_leaf(&dir, name, S_IFLNK | S_IRUGO | S_IXUGO))	    == NULL) {		PRINTK("(%s): could not prepare leaf\n", name);		kfree(newlink);		return -ENOTDIR;	}	de->info = NULL;	de->u.symlink.linkname = newlink;	de->u.symlink.length = linklength;	if ((err = _devfs_append_entry(dir, de, NULL)) != 0) {		PRINTK("(%s): could not append to parent, err: %d\n", name,		       err);		devfs_put(dir);		return err;	}	devfs_put(dir);#ifdef CONFIG_DEVFS_DEBUG	spin_lock(&stat_lock);	stat_num_bytes += linklength + 1;	spin_unlock(&stat_lock);#endif	if (handle != NULL)		*handle = de;	return 0;}				/*  End Function devfs_do_symlink  *//**

⌨️ 快捷键说明

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