Jul 02

在前一篇文章 RPC程序的一般结构 - nfsd 讲到了 RPC 程序的一般结构.

svc_recv 函数从所有的连接(svc_xprt)里尝试读取一个完整的请求(svc_rqst), 不过, 函数返回时, 可能没有任何就绪的请求, 所以, nfsd 代码中通过一个 while 循环读取请求.

while ((err = svc_recv(rqstp, 60*60*HZ)) == -EAGAIN)
	;

Continue reading »

Written by benegg at 2009-07-02 15:09:49 | tags:

Apr 23

通过diff工具生成补丁, patch工具打上补丁.

在使用diff之前, 你需要保留一份未修改过的源码, 然后在其它地方修改源码的一份拷贝. diff对比这两份源码生成patch. 修改过的源码必须保留原来的文件名, 例如, 如果你修改源码中的a.c文件, 那么, 修改后的文件还是名为a.c, 在修改之前你可以复制a.c为a.orig.c进行备份.

diff命令必须在整个Linux源码的根目录的上一级目录中执行.

1. 为单个文件生成补丁

diff -up linux-2.6.28.8/net/sunrpc/svc.orig.c linux-2.6.28.8/net/sunrpc/svc.c

这条命令会产生类似如下的输出, 你将它重定向到一个文件中, 这个文件就是patch.

--- linux-2.6.28.8/net/sunrpc/svc.orig.c 2009-03-17 08:50:04.000000000 +0800
+++ linux-2.6.28.8/net/sunrpc/svc.c 2009-03-30 19:18:41.859375000 +0800
@@ -1050,11 +1050,11 @@ svc_process(struct svc_rqst *rqstp)

参数详解:
-u 显示有差异行的前后几行(上下文), 默认是前后各3行, 这样, patch中带有更多的信息.
-p 显示代码所在的c函数的信息.

Continue reading »

Written by benegg at 2009-04-23 09:49:15 | tags:

Apr 16
/* file: net/sunrpc/svc.c */
struct svc_serv *svc_create(struct svc_program *, unsigned int, sa_family_t,
			    void (*shutdown)(struct svc_serv *));

实际上调用的是私有函数 __svc_create(), 分配 RPC 服务(svc_serv)的内存空间. 结构体 svc_server 是整个 RPC 服务(服务器/客户端)的表示. 和 svc_create_pooled 不同, 本函数一般用来创建 RPC 客户端[待求证?].

/* file: net/sunrpc/svc.c */
struct svc_serv *  svc_create_pooled(struct svc_program *, unsigned int,
			sa_family_t, void (*shutdown)(struct svc_serv *),
			svc_thread_fn, struct module *);

与 svc_create 类似, 一般用来创建 RPC 服务器, 因为它创建的是 RPC 服务的线程池. RPC 服务器需要使用线程池, 以便能并发的处理多个客户端的请求.

/* file: net/sunrpc/svc.c */
struct svc_rqst *svc_prepare_thread(struct svc_serv *serv,
					struct svc_pool *pool);

分配 RPC 服务线程所需的内存空间, 包括:

1. RPC 请求 svc_rqst
2. 解码之后的 RPC 请求 argp
3. 编码之前的 RPC 响应 resp,

解析之后的 RPC 请求, 是一个请求的语言相关表示, 在 Linux 源码中就是 C 语言表示. 如果使用 Java, 就可能是一个 Java 类. 所谓的语言相关, 是指在用相关的编程语言来描述的.

svc_rqst 既包含了语言相关的请求/响应表示, 也包含了请求/响应的字节数组表示.

/* file: net/sunrpc/svc.c */
void		   svc_exit_thread(struct svc_rqst *);

结束一个 RPC 服务器线程, 释放通过 svc_prepare_thread() 分配的所有空间, 同时还调用 svc_destroy() 销毁 svc_serv -- 我认为应该在 svc_exit_thread 之外调用 svc_destroy(), 因为 svc_serv 不是在 svc_prepare_thread() 里创建的.

/* file: net/sunrpc/svc.c */
void		   svc_destroy(struct svc_serv *);

销毁一个 RPC 服务, 关闭所有 socket 连接, 释放服务的线程池空间和其本身.

/* file: net/sunrpc/svc.c */
int		   svc_process(struct svc_rqst *);

在本函数中解码请求, 处理, 编码响应, 发送响应. 详见: svc_process函数.

TODO: Linux 的 RPC 实现中, svc_serv 分别在服务器和客户端的角色.

Written by benegg at 2009-04-16 16:59:59 | tags: ,

Apr 09

一个RPC程序所要做的工作就是: 读取请求, 处理请求, 返回响应. 以nfsd为例, 其实现代码如下所示. 处理请求和返回响应放在同一个函数svc_process()里.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/* in fs/nfsd/nfssvc.c: nfsd() */
 
struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp;
...
/*
 * The main request loop
 */
for (;;) {
	/*
	 * Find a socket with data available and call its
	 * recvfrom routine.
	 */
	while ((err = svc_recv(rqstp, 60*60*HZ)) == -EAGAIN)
		;
	if (err == -EINTR)
		break;
	else if (err < 0) {
		if (err != preverr) {
			printk(KERN_WARNING "%s: unexpected error "
				"from svc_recv (%d)\n", __func__, -err);
			preverr = err;
		}
		schedule_timeout_uninterruptible(HZ);
		continue;
	}
 
	update_thread_usage(atomic_read(&nfsd_busy));
	atomic_inc(&nfsd_busy);
 
	/* Lock the export hash tables for reading. */
	exp_readlock();
 
	svc_process(rqstp);
 
	/* Unlock export hash tables */
	exp_readunlock();
	update_thread_usage(atomic_read(&nfsd_busy));
	atomic_dec(&nfsd_busy);
}

svc_recv()接受结构体svc_rqst的指针作为参数, 如果正常返回, svc_rqst包含了RPC请求报文的字节数组. svc_rqst的内存是在svc_recv()进进行分配.

Written by benegg at 2009-04-09 16:50:50 | tags: ,