base.c

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

C
2,003
字号
 *	devfs_mk_symlink Create a symbolic link in the devfs namespace. *	@from: The name of the entry. *	@to: Name of the destination * *	Returns 0 on success, else a negative error code is returned. */int devfs_mk_symlink(const char *from, const char *to){	devfs_handle_t de;	int err;	err = devfs_do_symlink(NULL, from, to, &de);	if (!err) {		de->vfs = TRUE;		devfsd_notify(de, DEVFSD_NOTIFY_REGISTERED);	}	return err;}/** *	devfs_mk_dir - Create a directory in the devfs namespace. *		new name is relative to the root of the devfs. *	@fmt: The name of the entry. * *	Use of this function is optional. The devfs_register() function *	will automatically create intermediate directories as needed. This function *	is provided for efficiency reasons, as it provides a handle to a directory. *	On failure %NULL is returned. */int devfs_mk_dir(const char *fmt, ...){	struct devfs_entry *dir = NULL, *de = NULL, *old;	char buf[64];	va_list args;	int error, n;	va_start(args, fmt);	n = vsnprintf(buf, 64, fmt, args);	if (n >= 64 || !buf[0]) {		printk(KERN_WARNING "%s: invalid argument.", __FUNCTION__);		return -EINVAL;	}	de = _devfs_prepare_leaf(&dir, buf, MODE_DIR);	if (!de) {		PRINTK("(%s): could not prepare leaf\n", buf);		return -EINVAL;	}	error = _devfs_append_entry(dir, de, &old);	if (error == -EEXIST && S_ISDIR(old->mode)) {		/*		 * devfs_mk_dir() of an already-existing directory will		 * return success.		 */		error = 0;		goto out_put;	} else if (error) {		PRINTK("(%s): could not append to dir: %p \"%s\"\n",		       buf, dir, dir->name);		devfs_put(old);		goto out_put;	}	devfsd_notify(de, DEVFSD_NOTIFY_REGISTERED);      out_put:	devfs_put(dir);	return error;}void devfs_remove(const char *fmt, ...){	char buf[64];	va_list args;	int n;	va_start(args, fmt);	n = vsnprintf(buf, sizeof(buf), fmt, args);	if (n < sizeof(buf) && buf[0]) {		devfs_handle_t de = _devfs_find_entry(NULL, buf, 0);		if (!de) {			printk(KERN_ERR "%s: %s not found, cannot remove\n",			       __FUNCTION__, buf);			dump_stack();			return;		}		write_lock(&de->parent->u.dir.lock);		_devfs_unregister(de->parent, de);		devfs_put(de);		devfs_put(de);	}}/** *	devfs_generate_path - Generate a pathname for an entry, relative to the devfs root. *	@de: The devfs entry. *	@path: The buffer to write the pathname to. The pathname and '\0' *		terminator will be written at the end of the buffer. *	@buflen: The length of the buffer. * *	Returns the offset in the buffer where the pathname starts on success, *	else a negative error code. */static int devfs_generate_path(devfs_handle_t de, char *path, int buflen){	int pos;#define NAMEOF(de) ( (de)->mode ? (de)->name : (de)->u.name )	if (de == NULL)		return -EINVAL;	VERIFY_ENTRY(de);	if (de->namelen >= buflen)		return -ENAMETOOLONG;	/*  Must be first       */	path[buflen - 1] = '\0';	if (de->parent == NULL)		return buflen - 1;	/*  Don't prepend root  */	pos = buflen - de->namelen - 1;	memcpy(path + pos, NAMEOF(de), de->namelen);	for (de = de->parent; de->parent != NULL; de = de->parent) {		if (pos - de->namelen - 1 < 0)			return -ENAMETOOLONG;		path[--pos] = '/';		pos -= de->namelen;		memcpy(path + pos, NAMEOF(de), de->namelen);	}	return pos;}				/*  End Function devfs_generate_path  *//** *	devfs_setup - Process kernel boot options. *	@str: The boot options after the "devfs=". */static int __init devfs_setup(char *str){	static struct {		char *name;		unsigned int mask;		unsigned int *opt;	} devfs_options_tab[] __initdata = {#ifdef CONFIG_DEVFS_DEBUG		{		"dall", DEBUG_ALL, &devfs_debug_init}, {		"dmod", DEBUG_MODULE_LOAD, &devfs_debug_init}, {		"dreg", DEBUG_REGISTER, &devfs_debug_init}, {		"dunreg", DEBUG_UNREGISTER, &devfs_debug_init}, {		"dfree", DEBUG_FREE, &devfs_debug_init}, {		"diget", DEBUG_I_GET, &devfs_debug_init}, {		"dchange", DEBUG_SET_FLAGS, &devfs_debug_init}, {		"dsread", DEBUG_S_READ, &devfs_debug_init}, {		"dichange", DEBUG_I_CHANGE, &devfs_debug_init}, {		"dimknod", DEBUG_I_MKNOD, &devfs_debug_init}, {		"dilookup", DEBUG_I_LOOKUP, &devfs_debug_init}, {		"diunlink", DEBUG_I_UNLINK, &devfs_debug_init},#endif				/*  CONFIG_DEVFS_DEBUG  */		{		"mount", OPTION_MOUNT, &boot_options}, {		NULL, 0, NULL}	};	while ((*str != '\0') && !isspace(*str)) {		int i, found = 0, invert = 0;		if (strncmp(str, "no", 2) == 0) {			invert = 1;			str += 2;		}		for (i = 0; devfs_options_tab[i].name != NULL; i++) {			int len = strlen(devfs_options_tab[i].name);			if (strncmp(str, devfs_options_tab[i].name, len) == 0) {				if (invert)					*devfs_options_tab[i].opt &=					    ~devfs_options_tab[i].mask;				else					*devfs_options_tab[i].opt |=					    devfs_options_tab[i].mask;				str += len;				found = 1;				break;			}		}		if (!found)			return 0;	/*  No match         */		if (*str != ',')			return 0;	/*  No more options  */		++str;	}	return 1;}				/*  End Function devfs_setup  */__setup("devfs=", devfs_setup);EXPORT_SYMBOL(devfs_mk_symlink);EXPORT_SYMBOL(devfs_mk_dir);EXPORT_SYMBOL(devfs_remove);/** *	try_modload - Notify devfsd of an inode lookup by a non-devfsd process. *	@parent: The parent devfs entry. *	@fs_info: The filesystem info. *	@name: The device name. *	@namelen: The number of characters in @name. *	@buf: A working area that will be used. This must not go out of scope *            until devfsd is idle again. * *	Returns 0 on success (event was queued), else a negative error code. */static int try_modload(struct devfs_entry *parent, struct fs_info *fs_info,		       const char *name, unsigned namelen,		       struct devfs_entry *buf){	if (!(fs_info->devfsd_event_mask & (1 << DEVFSD_NOTIFY_LOOKUP)))		return -ENOENT;	if (is_devfsd_or_child(fs_info))		return -ENOENT;	memset(buf, 0, sizeof *buf);	atomic_set(&buf->refcount, 1);	buf->parent = parent;	buf->namelen = namelen;	buf->u.name = name;	WRITE_ENTRY_MAGIC(buf, MAGIC_VALUE);	if (!devfsd_notify_de(buf, DEVFSD_NOTIFY_LOOKUP, 0,			      current->euid, current->egid, fs_info))		return -ENOENT;	/*  Possible success: event has been queued  */	return 0;}				/*  End Function try_modload  *//*  Superblock operations follow  */static struct inode_operations devfs_iops;static struct inode_operations devfs_dir_iops;static struct file_operations devfs_fops;static struct file_operations devfs_dir_fops;static struct inode_operations devfs_symlink_iops;static int devfs_notify_change(struct dentry *dentry, struct iattr *iattr){	int retval;	struct devfs_entry *de;	struct inode *inode = dentry->d_inode;	struct fs_info *fs_info = inode->i_sb->s_fs_info;	de = get_devfs_entry_from_vfs_inode(inode);	if (de == NULL)		return -ENODEV;	retval = inode_change_ok(inode, iattr);	if (retval != 0)		return retval;	retval = inode_setattr(inode, iattr);	if (retval != 0)		return retval;	DPRINTK(DEBUG_I_CHANGE, "(%d): VFS inode: %p  devfs_entry: %p\n",		(int)inode->i_ino, inode, de);	DPRINTK(DEBUG_I_CHANGE, "():   mode: 0%o  uid: %d  gid: %d\n",		(int)inode->i_mode, (int)inode->i_uid, (int)inode->i_gid);	/*  Inode is not on hash chains, thus must save permissions here rather	   than in a write_inode() method  */	de->mode = inode->i_mode;	de->inode.uid = inode->i_uid;	de->inode.gid = inode->i_gid;	de->inode.atime = inode->i_atime;	de->inode.mtime = inode->i_mtime;	de->inode.ctime = inode->i_ctime;	if ((iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)) &&	    !is_devfsd_or_child(fs_info))		devfsd_notify_de(de, DEVFSD_NOTIFY_CHANGE, inode->i_mode,				 inode->i_uid, inode->i_gid, fs_info);	return 0;}				/*  End Function devfs_notify_change  */static struct super_operations devfs_sops = {	.drop_inode = generic_delete_inode,	.statfs = simple_statfs,};/** *	_devfs_get_vfs_inode - Get a VFS inode. *	@sb: The super block. *	@de: The devfs inode. *	@dentry: The dentry to register with the devfs inode. * *	Returns the inode on success, else %NULL. An implicit devfs_get() is *       performed if the inode is created. */static struct inode *_devfs_get_vfs_inode(struct super_block *sb,					  struct devfs_entry *de,					  struct dentry *dentry){	struct inode *inode;	if (de->prev == de)		return NULL;	/*  Quick check to see if unhooked  */	if ((inode = new_inode(sb)) == NULL) {		PRINTK("(%s): new_inode() failed, de: %p\n", de->name, de);		return NULL;	}	if (de->parent) {		read_lock(&de->parent->u.dir.lock);		if (de->prev != de)			de->inode.dentry = dentry;	/*      Not unhooked  */		read_unlock(&de->parent->u.dir.lock);	} else		de->inode.dentry = dentry;	/*  Root: no locking needed  */	if (de->inode.dentry != dentry) {	/*  Must have been unhooked  */		iput(inode);		return NULL;	}	/* FIXME where is devfs_put? */	inode->u.generic_ip = devfs_get(de);	inode->i_ino = de->inode.ino;	DPRINTK(DEBUG_I_GET, "(%d): VFS inode: %p  devfs_entry: %p\n",		(int)inode->i_ino, inode, de);	inode->i_blocks = 0;	inode->i_blksize = FAKE_BLOCK_SIZE;	inode->i_op = &devfs_iops;	inode->i_mode = de->mode;	if (S_ISDIR(de->mode)) {		inode->i_op = &devfs_dir_iops;		inode->i_fop = &devfs_dir_fops;	} else if (S_ISLNK(de->mode)) {		inode->i_op = &devfs_symlink_iops;		inode->i_size = de->u.symlink.length;	} else if (S_ISCHR(de->mode) || S_ISBLK(de->mode)) {		init_special_inode(inode, de->mode, de->u.dev);	} else if (S_ISFIFO(de->mode) || S_ISSOCK(de->mode)) {		init_special_inode(inode, de->mode, 0);	} else {		PRINTK("(%s): unknown mode %o de: %p\n",		       de->name, de->mode, de);		iput(inode);		devfs_put(de);		return NULL;	}	inode->i_uid = de->inode.uid;	inode->i_gid = de->inode.gid;	inode->i_atime = de->inode.atime;	inode->i_mtime = de->inode.mtime;	inode->i_ctime = de->inode.ctime;	DPRINTK(DEBUG_I_GET, "():   mode: 0%o  uid: %d  gid: %d\n",		(int)inode->i_mode, (int)inode->i_uid, (int)inode->i_gid);	return inode;}				/*  End Function _devfs_get_vfs_inode  *//*  File operations for device entries follow  */static int devfs_readdir(struct file *file, void *dirent, filldir_t filldir){	int err, count;	int stored = 0;	struct fs_info *fs_info;	struct devfs_entry *parent, *de, *next = NULL;	struct inode *inode = file->f_dentry->d_inode;	fs_info = inode->i_sb->s_fs_info;	parent = get_devfs_entry_from_vfs_inode(file->f_dentry->d_inode);	if ((long)file->f_pos < 0)		return -EINVAL;	DPRINTK(DEBUG_F_READDIR, "(%s): fs_info: %p  pos: %ld\n",		parent->name, fs_info, (long)file->f_pos);	switch ((long)file->f_pos) {	case 0:		err = (*filldir) (dirent, "..", 2, file->f_pos,				  parent_ino(file->f_dentry), DT_DIR);		if (err == -EINVAL)			break;		if (err < 0)			return err;		file->f_pos++;		++stored;		/*  Fall through  */	case 1:		err =		    (*filldir) (dirent, ".", 1, file->f_pos, inode->i_ino,				DT_DIR);		if (err == -EINVAL)			break;		if (err < 0)			return err;		file->f_pos++;		++stored;		/*  Fall through  */	default:		/*  Skip entries  */		count = file->f_pos - 2;		read_lock(&parent->u.dir.lock);		for (de = parent->u.dir.first; de && (count > 0); de = de->next)		

⌨️ 快捷键说明

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