内核ceph_mount流程
内核ceph_mount流程
1. 用户空间命令行发起 mount 请求
mount -t ceph $(hostname):6789:/ /mnt/ceph/ -o name=admin,secret=$(ceph auth get-key client.admin)
执行这条ceph挂载命令时会发生什么?
2. 进入内核 sys_mount 系统调用
SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
char __user *, type, unsigned long, flags, void __user *, data)
sys_mount 接受用户传入的设备名、挂载点、文件系统类型、挂载标志和挂载选项。
它将参数传递给 do_mount() 函数,进行更详细的挂载操作。
3. do_mount() 函数
long do_mount(const char *dev_name, const char __user *dir_name,
const char *type_page, unsigned long flags, void *data_page)
do_mount 函数负责解析和检查挂载参数。
调用 do_new_mount 函数,尝试将文件系统挂载到指定路径。
4. do_new_mount() 函数
static int do_new_mount(struct path *path, const char *fstype, int flags,
int mnt_flags, const char *name, void *data)
do_new_mount 主要负责创建 vfsmount 结构并调用 vfs_kern_mount 函数,向虚拟文件系统(VFS)提交挂载请求。
vfsmount 是一个内核结构体,用于在 VFS 中表示文件系统的挂载点,包含挂载的信息和路径。
5. vfs_kern_mount() 函数
struct vfsmount *
vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
vfs_kern_mount 是挂载路径的关键函数,它通过文件系统类型(file_system_type)找到具体的挂载函数,并创建一个 vfsmount 结构。
调用 type->mount(),即调用对应文件系统类型的 mount 函数。
对于 Ceph 文件系统,file_system_type 是 ceph_fs_type,它的 mount 函数是 ceph_mount()。
6. ceph_mount() 函数
static struct dentry *ceph_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
ceph_mount 是 Ceph 文件系统特有的挂载函数。
ceph_mount 主要负责初始化 Ceph 文件系统客户端,连接到 Ceph 集群,并创建文件系统的根目录(dentry)。
ceph_mount 使用 Ceph 的用户态库(libceph)进行 Ceph 集群通信,包括连接到 Ceph Monitor、OSD 等服务。
挂载成功后返回根目录 dentry 给 VFS。
详细看一下代码!!!
ceph mount过程,主要在fs/ceph/super.c文件中。
ceph_mount解析挂载选项,创建文件客户端,初始化mds客户端,然后进入到ceph_real_mount;ceph_real_mount 将客户端节点挂载到 Ceph 文件系统集群,并打开文件系统的根目录。其中__ceph_open_session - ceph_monc_open_session建立与mon的连接。open_root_dentry - ceph_mdsc_create_request建立与mds的连接。
static struct dentry *ceph_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
struct super_block *sb;
struct ceph_fs_client *fsc;
struct dentry *res;
int err;
int (*compare_super)(struct super_block *, void *) = ceph_compare_super;
struct ceph_mount_options *fsopt = NULL;
struct ceph_options *opt = NULL;
dout("ceph_mount\n");
#ifdef CONFIG_CEPH_FS_POSIX_ACL
flags |= MS_POSIXACL;
#endif
err = parse_mount_options(&fsopt, &opt, flags, data, dev_name);
if (err < 0) {
res = ERR_PTR(err);
goto out_final;
}
/* create client (which we may/may not use) */
fsc = create_fs_client(fsopt, opt);
if (IS_ERR(fsc)) {
res = ERR_CAST(fsc);
destroy_mount_options(fsopt);
ceph_destroy_options(opt);
goto out_final;
}
err = ceph_mdsc_init(fsc);
if (err < 0) {
res = ERR_PTR(err);
goto out;
}
if (ceph_test_opt(fsc->client, NOSHARE))
compare_super = NULL;
sb = sget(fs_type, compare_super, ceph_set_super, flags, fsc);
if (IS_ERR(sb)) {
res = ERR_CAST(sb);
goto out;
}
if (ceph_sb_to_client(sb) != fsc) {
ceph_mdsc_destroy(fsc);
destroy_fs_client(fsc);
fsc = ceph_sb_to_client(sb);
dout("get_sb got existing client %p\n", fsc);
} else {
dout("get_sb using new client %p\n", fsc);
err = ceph_register_bdi(sb, fsc);
if (err < 0) {
res = ERR_PTR(err);
goto out_splat;
}
}
res = ceph_real_mount(fsc);
if (IS_ERR(res))
goto out_splat;
dout("root %p inode %p ino %llx.%llx\n", res,
res->d_inode, ceph_vinop(res->d_inode));
return res;
out_splat:
ceph_mdsc_close_sessions(fsc->mdsc);
deactivate_locked_super(sb);
goto out_final;
out:
ceph_mdsc_destroy(fsc);
destroy_fs_client(fsc);
out_final:
dout("ceph_mount fail %ld\n", PTR_ERR(res));
return res;
}
static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc)
{
int err;
unsigned long started = jiffies; /* note the start time */
struct dentry *root;
dout("mount start %p\n", fsc);
mutex_lock(&fsc->client->mount_mutex);
if (!fsc->sb->s_root) {
const char *path;
err = __ceph_open_session(fsc->client, started);
if (err < 0)
goto out;
if (!fsc->mount_options->server_path) {
path = "";
dout("mount opening path \\t\n");
} else {
path = fsc->mount_options->server_path + 1;
dout("mount opening path %s\n", path);
}
err = ceph_fs_debugfs_init(fsc);
if (err < 0)
goto out;
root = open_root_dentry(fsc, path, started);
if (IS_ERR(root)) {
err = PTR_ERR(root);
goto out;
}
fsc->sb->s_root = dget(root);
} else {
root = dget(fsc->sb->s_root);
}
fsc->mount_state = CEPH_MOUNT_MOUNTED;
dout("mount success\n");
mutex_unlock(&fsc->client->mount_mutex);
return root;
out:
mutex_unlock(&fsc->client->mount_mutex);
return ERR_PTR(err);
}
7. 返回到用户空间
挂载成功后,sys_mount 返回到用户空间,mount 命令得到返回结果。
此时,Ceph 文件系统的根目录已经挂载在指定的挂载点,用户可以通过挂载点访问 Ceph 文件系统。
查看日志
在/var/log/messages中只看到这两条相关日志。
Nov xx 11:03:56 node1 kernel: libceph: mon0 192.xxx.xxx.xxx:6789 session established
Nov xx 11:03:56 node1 kernel: libceph: client50981349 fsid ed69ef4c-63ed-436f-a733-c53c0037105d
以上日志信息远远不够,准备提高内核日志打印级别继续看看。
内核日志级别调整
内核日志级别可以通过/proc/sys/kernel/printk文件来修改
先来看看这个文件初始是什么样子
[root@node1 ~]# cat /proc/sys/kernel/printk
4 4 1 7
这四个值的定义可以在kernel/printk.c中找到
int console_printk[4] = {
DEFAULT_CONSOLE_LOGLEVEL, /* console_loglevel */
DEFAULT_MESSAGE_LOGLEVEL, /* default_message_loglevel */
MINIMUM_CONSOLE_LOGLEVEL, /* minimum_console_loglevel */
DEFAULT_CONSOLE_LOGLEVEL, /* default_console_loglevel */
};
而内核日志级别有以下七种
#define KERN_EMERG KERN_SOH "0" /* system is unusable */
#define KERN_ALERT KERN_SOH "1" /* action must be taken immediately */
#define KERN_CRIT KERN_SOH "2" /* critical conditions */
#define KERN_ERR KERN_SOH "3" /* error conditions */
#define KERN_WARNING KERN_SOH "4" /* warning conditions */
#define KERN_NOTICE KERN_SOH "5" /* normal but significant condition */
#define KERN_INFO KERN_SOH "6" /* informational */
#define KERN_DEBUG KERN_SOH "7" /* debug-level messages */
#define KERN_DEFAULT KERN_SOH "d" /* the default kernel loglevel */
只需要调整对应数字就可以,比如
echo 8 4 1 7 > /proc/sys/kernel/printk
注意:控制台只会显示大于所设置等级的信息,比如想要看debug(7)日志信息,需要设置为7以上
方法二:
确保/etc/rsyslog.conf文件中 #kern.* 注释被取消!
systemctl restart rsyslog
这样内核产生的所有日志信息都会被记录到相应的文件中,包括 dout 产生的调试信息。
补充:
dmesg的信息在环缓冲区中,只包含最新的内核日志;
/var/log/messages是磁盘上的文件,保留较长时间的日志记录。
补充 - 内核开启DEBUG
在生产环境中,出于安全和性能的考虑,可能会禁用调试信息,这时候调整日志打印级别是不生效的,这时候需要在内核代码中打开DEBUG
方法一
修改Makefile文件,比如我们要打开fs/ceph/下所有文件及子目录下的DEBUG宏,可以在fs/ceph/Makefile中添加subdir-ccflags-y := -DDEBUG选项
方法二
在pr_debug/dev_dbg模块最上面加上#define DEBUG语句
开启之后,在dmesg中就可以看到pr_debug/dev_dbg的打印信息了。

浙公网安备 33010602011771号