从mount -o一些理解结合cfs进行描述,窥探该项目全局。
mount命令中除了常见的-t 也就是选择挂在文件系统的类型。还有一个重要的参数-o
这个参数里面可以携带很多参数,比如设定挂在的用户名,密码等等,但是这些参数怎么接受呢,也就是具体会传递到哪里呢?
首先注册文件系统的时候,有个数据结构file_system_type
如cfs的文件系统定义如下:
static struct file_system_type cfs_fs_type = {
.owner = THIS_MODULE,
.name = "cfs",
.get_sb = cfs_get_sb,
.kill_sb = kill_litter_super,
.fs_flags = 0,
};
这个参数是要传递给文件系统注册函数 register_filesystem(&cfs_file_system)的。
当我们调用mount的时候,一定会转到cfs_get_sb这个函数。
该函数调用cfs_fill_super(struct super_block *sb, void *data, int silent)
在这个函数中可以接收shell下传入的参数。
比如,在shell下有如下调用:
mount -t cfs -o mds=192.168.0.81 -o port=2123 -o user=$1 -o pwd=root -o semethod=$SEMETHOD seclient /mnt/cfs
那么在cfs_fill_super里面就有以下的命令解析:
while (ptr&&strlen(ptr))
{
if ((ptr2=strchr(ptr, ','))) {
strncpy(opt, ptr, ptr2-ptr);
opt[ptr2-ptr] = '\0';
ptr = ptr2+1;
} else {
strcpy(opt, ptr);
ptr = '\0';
}
if (!strncmp(opt, "user=", 5)) {
memset(user,0,20);
if(sscanf(opt, "user=%s", user)!=1){
TRACE_ERROR("malformed option \"%s\"\n", opt);
goto failed_mount;
}
TRACE(TRACE_OFI, 0, "user=%s\n",user);
} else if (!strncmp(opt, "pwd=", 4)) {
memset(pwd,0,20);
if(sscanf(opt, "pwd=%s", pwd)!=1){
TRACE_ERROR("malformed option \"%s\"\n", opt);
goto failed_mount;
}
TRACE(TRACE_OFI, 0, "pwd=%s\n",pwd);
} else if (!strncmp(opt, "mds=", 4)) {
if (sscanf(opt, "mds=%s", mds_ip)!=1) {
TRACE_ERROR("malformed option \"%s\"\n", opt);
goto failed_mount;
}
TRACE(TRACE_OFI, 0, "mds ip=%s\n",mds_ip);
} else if (!strncmp(opt, "port=", 5)) {
if (sscanf(opt, "port=%d", &mds_port)!=1) {
TRACE_ERROR("malformed option \"%s\"\n", opt);
goto failed_mount;
}
TRACE(TRACE_OFI, 0, "mds port=%d\n",mds_port);
} else if(!strncmp(opt, "semethod=", 9)){
if(sscanf(opt, "semethod=%d", &semeth)!=1) {
TRACE_ERROR("malformed option \"%s\"\n", opt);
goto failed_mount;
}
TRACE(TRACE_OFI, 0, "semethod=%d\n", semeth);
} else {
TRACE_ERROR("unknown option \"%s\"\n", opt);
goto failed_mount;
}
(上面为非完整代码,待补充)
这里面就提取出来了下面的几个信息:MDS IP, 端口号,用户名,密码 ,安全模式等信息。
然后作为参数传递给 mds_login(mds_ip,mds_port,user,pwd).cfs_fill_super继续完成后面文件系统需要完成的东西。做安全的只是在这里做了上述改动。
当然mds_login()函数,在里面做了一些初始化,只要是做了一个iscsi通道的链接。这个链接当然需要用到 mds的IP地址,以及端口号,也就是网络的一个套接字。
然后调用login(user,pwd)这里只需要传递用户名和密码。
login函数,需要根据semeth也就是安全模式的不同,进行不同的初始化,比如某个模式需要调用client_sign函数来进行签名。其中里面做的很重要的一点就是把用户名,密码,角色,userid等信息都放在一个结构体,叫user_cmd然后传递给client_sign()函数进行签名。签名完成之后,条用函数send2server(&suer_cmd)传递给mds。
send2server函数。
send2server(struct mds_request *user_cmd)
该函数主要做了一下工作:
首先如果安全模式有要求的话,那么调用aes库进行加密。参数0,1分别代表加解密
加密后的东西放在cdb字符串中,然后调用信息发送命令将刚才的请求发送给mds
注意iscsi_socket_msg函数的第二个参数,如果是1表示发送信息,如果是0表示接受信息。
接受的信息依然是放在cdb缓冲区的。
然后如果上面的进行了加密过程的安全模式,那么这里是需要解密的。MDS是加密发送的,这边也是要解密的,总之是对应的关系。
里面很多细节处理,比如,如果是MDS_GETACL的话就调用print_acl来打印对应的acl表,
这里基本完成的命令有:首先 ./start user1这个是主要是mount,里面会把opcode设置为MDS_LOGIN。然后调用send2server完成mount操作。
如果是元数据请求的话,最后得到的就是元数据。
如果是./llx 查看访问控制列表,那么就到MDS拿到ACL表,然后打印。
如果是 ./chomodx 把命令传递过去,然后mds接到命令后,修改acl表。
因此主要的工作都是要通过 send2server函数来完成的。