linux驱动说开去(七)--驱动模块之应用层访问-mknod

概述:

    linux下一切皆文件,设备文件也不例外,作为文件系统中代表设备的特殊文件,和普通文件相比不需要存放数据的记录块与之联系,原因在于设备文件的目的不在于存储和读取数据而只在于为应用程序提供一条通向具体设备的访问通道,是应用程序可以和具体的设备建立连接.

    基于此,我们查看内核系统调用针对两者的区别:

asmlinkage long sys_open(const char * filename, int flags, int mode)
asmlinkage long sys_creat(const char * pathname, int mode)
asmlinkage long sys_mknod(const char * filename, int mode, dev_t dev)

    普通文件的创建方式:sys_open(O_CREAT=1),create,sys__creat实则也是调用sys_open来实现

    设备文件:sys_mknod多出了设备号参数,这也是区分设备必要的

    总结:sys_mknod是通用的,可以创建除目录外的任何文件,sys_open/sys_creat用来创建普通文件,sys_pipe用来创建FIFO文件,通常来讲sys_mknod主要用于创建设备文件,只是纯粹创建而非像sys_open/sys_creat集创建打开于一体

    sys_mknod(const char * filename, int mode, dev_t dev)原型

asmlinkage long sys_mknod(const char * filename, int mode, dev_t dev)
{
	int error = 0;
	char * tmp;
	struct dentry * dentry;
	struct nameidata nd;

	if (S_ISDIR(mode))
		return -EPERM;
	tmp = getname(filename);
	if (IS_ERR(tmp))
		return PTR_ERR(tmp);

	if (path_init(tmp, LOOKUP_PARENT, &nd))
		error = path_walk(tmp, &nd);
	if (error)
		goto out;
	dentry = lookup_create(&nd, 0);
	error = PTR_ERR(dentry);
	if (!IS_ERR(dentry)) {
		switch (mode & S_IFMT) {
		case 0: case S_IFREG:
			error = vfs_create(nd.dentry->d_inode,dentry,mode);//普通文件创建
			break;
		case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK:
			error = vfs_mknod(nd.dentry->d_inode,dentry,mode,dev);//字符设备,块设备,fifo,socket设备文件创建
			break;
		case S_IFDIR:
			error = -EPERM;
			break;
		default:
			error = -EINVAL;
		}
		dput(dentry);
	}
	up(&nd.dentry->d_inode->i_sem);
	path_release(&nd);
out:
	putname(tmp);

	return error;
}

int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
{
    int error = -EPERM;

    mode &= ~current->fs->umask;

    down(&dir->i_zombie);
    if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD))
        goto exit_lock;

    error = may_create(dir, dentry);
    if (error)
        goto exit_lock;

    error = -EPERM;
    if (!dir->i_op || !dir->i_op->mknod)
        goto exit_lock;

    DQUOT_INIT(dir);
    lock_kernel();
    error = dir->i_op->mknod(dir, dentry, mode, dev);//只想实际的文件系统
    unlock_kernel();
exit_lock:
    up(&dir->i_zombie);
    if (!error)
        inode_dir_notify(dir, DN_CREATE);
    return error;
}
//实际文件系统接口
static int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
{
    struct inode * inode = ext2_new_inode (dir, mode);
    int err = PTR_ERR(inode);

    if (IS_ERR(inode))
        return err;

    inode->i_uid = current->fsuid;
    init_special_inode(inode, mode, rdev);//针对不同设备绑定对应fop
    err = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, 
                 inode);
    if (err)
        goto out_no_entry;
    mark_inode_dirty(inode);
    d_instantiate(dentry, inode);
    return 0;

out_no_entry:
    inode->i_nlink--;
    mark_inode_dirty(inode);
    iput(inode);
    return err;
}
void init_special_inode(struct inode *inode, umode_t mode, int rdev)
{
    inode->i_mode = mode;
    if (S_ISCHR(mode)) {
        inode->i_fop = &def_chr_fops;
        inode->i_rdev = to_kdev_t(rdev);
    } else if (S_ISBLK(mode)) {
        inode->i_fop = &def_blk_fops;
        inode->i_rdev = to_kdev_t(rdev);
        inode->i_bdev = bdget(rdev);
    } else if (S_ISFIFO(mode))
        inode->i_fop = &def_fifo_fops;
    else if (S_ISSOCK(mode))
        inode->i_fop = &bad_sock_fops;
    else
        printk(KERN_DEBUG "init_special_inode: bogus imode (%o)\n", mode);
}

以字符设备hello.ko为例:

filp->f_op->open实际指向了hello_mod_open

int chrdev_open(struct inode * inode, struct file * filp)
{
	int ret = -ENODEV;

	filp->f_op = get_chrfops(MAJOR(inode->i_rdev), MINOR(inode->i_rdev));
	if (filp->f_op) {
		ret = 0;
		if (filp->f_op->open != NULL) {
			lock_kernel();
			ret = filp->f_op->open(inode,filp);
			unlock_kernel();
		}
	}
	return ret;
}

    


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值