在Linux中,由于没有对应的物理设备,RPC管道文件系统是作为一种虚拟的文件系统存在的,其在系统中的注册和注销等操作都必须遵循Linux文件系统规范。关于RPC管道的实现主要分布在rpc_pipe.c文件中。下面是RPC管道文件系统在sunrpc_syms.c文件中的初始化过程:
        代码1-1  RPC管道文件系统的初始化过程
static int __init  init_sunrpc(void)		//__init表示该函数只在初始化过程中调用
    {
	        int err=register_rpc_pipefs();			//注册RPC管道文件系统"rpc_pipefs"
	        if (err)
		        goto out;
	        err=rpc_init_mempool();				//初始化内存池
	        if (err) {
		        unregister_rpc_pipefs();			//注销RPC管道文件系统"rpc_pipefs"
		        goto out;
	        }
        #ifdef RPC_DEBUG
	        rpc_register_sysctl();				//注册SYSCTL,方便用户读取或调整系统设置
    #endif
    #ifdef CONFIG_PROC_FS
	        rpc_proc_init();						//初始化PROC,方便用户获取运行时信息
    #endif
	        cache_register(&ip_map_cache);						//注册缓冲
	        cache_register(&unix_gid_cache);
	        svc_init_xprt_sock();
	    init_socket_xprt();								//初始化套接字
	        rpcauth_init_module();							//初始化RPC鉴权模块
    out:
	        return err;
    }
和其他文件系统一样,一个RPC管道是作为RPC管道文件系统下的一个文件存在的,下面是RPC管道的接口定义:
static const struct file_operations rpc_pipe_fops={
	    .owner=THIS_MODULE,
	    .llseek=no_llseek,
	    .read=rpc_pipe_read,			//读取管道数据
	    .write=rpc_pipe_write,		//写入管道数据
	    .poll=rpc_pipe_poll,			//轮询管道
	    .ioctl=rpc_pipe_ioctl,	   	//管道的ioctl
	    .open=rpc pipe_open,			//打开管道
	    .release=rpc_pipe_release,		//释放管道
    };
一个RPC管道就是RPC管道文件系统的一个节点,下面是RPC节点的定义:
struct rpc_inode {
	    struct inode vfs_inode;				//继承VFS节点
	    void *private;
	    struct list_head pipe;
	    struct list_head in_upcall;			//通知上层节点
	    struct list_head in_downcall;			//通知下层节点
	    int pipelen;			
	    int nreaders;							//读数据线程数
	    int nwriters;							//写数据线程数
	    int nkern_readwriters;
	    wait_queue_head_t waitq;				//等待队列
    #define RPC_PIPE_WAIT_FOR_OPEN	1
	    int flags;
	    struct rpc_pipe_ops *ops;				//管道选项
	    struct delayed_work queue_timeout;	
    };
    struct rpc_pipe_ops {
	    ssize_t (*upcall)(struct file *, struct rpc_pipe_msg *, char __user *, size_t);
	    ssize_t (*downcall)(struct file *, const char __user *, size_t);
	    void (*release_pipe)(struct inode *);			//释放管道
	    int (*open_pipe)(struct inode *);				//打开管道
	    void (*destroy_msg)(struct rpc_pipe_msg *);		//销毁管道消息
    };
为了利用RPC在Linux内核和用户空间之间进行通信,需要创建一个RPC管道,下面是创建一个RPC管道的实现过程:
代码1-2  创建RPC管道的过程
struct dentry * rpc_mkpipe(struct dentry *parent, const char *name, void *private, struct rpc_pipe_ops *ops, int flags)
    {
	    struct dentry *dentry;
	    struct inode *dir, *inode;
	    struct rpc_inode *rpci;
	    dentry=rpc_lookup_create(parent, name, strlen(name), 0);	//创建目录
	    if (IS_ERR(dentry))
		        return dentry;
	    dir=parent->d_inode;
	    if (dentry->d_inode) {
		        rpci=RPC_I(dentry->d_inode);
		        if (rpci->private !=private ||
				            rpci->ops !=ops ||
				            rpci->flags !=flags) {
			            dput (dentry);
			            dentry=ERR_PTR(-EBUSY);
		        }
		        rpci->nkern_readwriters++;
		        goto out;
	    }
	    inode=rpc_get_inode(dir->i_sb, S_IFIFO | S_IRUSR | S_IWUSR); //配置权限
	    if (!inode)
		        goto err_dput;
	    inode->i_ino=iunique(dir->i_sb, 100);
	    inode->i_fop=&rpc_pipe_fops;
	    d_instantiate(dentry, inode);
	    rpci=RPC_I(inode);
	    rpci->private=private;
	    rpci->flags=flags;
	    rpci->ops=ops;
	    rpci->nkern_readwriters=1;
	    fsnotify_create(dir, dentry);
	    dget(dentry);
    out:
	        mutex_unlock(&dir->i_mutex);
	        return dentry;
    err_dput:
	        dput(dentry);
	        dentry=ERR_PTR(-ENOMEM);
	        printk(KERN_WARNING "%s: %s() failed to create pipe %s/%s (errno=%d)\n",__FILE__, __func__, parent->d_name.name, name,-ENOMEM);
	        goto out;
    }
通过RPC管道文件系统,调用者可以像操作其他文件那样进行RPC管道的操作,常见的操作有读取数据、写入数据、查询管道信息、创建路径、删除路径、创建RPC管道等。
需要说明的是,当管道数据可读时,需要调用rpc_queue_upcall()函数通知用户空间,当管道可写入数据时,则不需要通知用户空间。在通知用户空间RPC管道的状态时,需要将消息封装在rpc_pipe_msg结构体中。下面是rpc_queue_upcall()函数的实现过程:
代码1-3  RPC通知用户空间的过程
int rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg)
    {
	        struct rpc_inode *rpci=RPC_I(inode);
	        int res=-EPIPE;
	        spin_lock(&inode->i_lock);		//自旋锁
	        if (rpci->ops==NULL)
		            goto out;
	        if (rpci->nreaders) {
		            list_add_tail(&msg->list, &rpci->pipe);	//添加到消息队列
		            rpci->pipelen+=msg->len;
		            res=0;
	        } else if (rpci->flags & RPC_PIPE_WAIT_FOR_OPEN) {	//如果RPC管道等待打开
		        if (list_empty(&rpci->pipe))
			            queue_delayed_work(rpciod_workqueue,		//添加到rpciod_workqueue
					&rpci->queue_timeout,
					            RPC_UPCALL_TIMEOUT);
		        list_add_tail(&msg->list, &rpci->pipe);			//添加到消息队列
		        rpci->pipelen += msg->len;
		        res=0;
	        }
        out:
	        spin_unlock(&inode->i_lock);
	        wake_up(&rpci->waitq);							//唤醒等待队列
	        return res;
    }
在auth_gss.c文件中,有RPC管道的运用实例,感兴趣的朋友可以自行研读。